go.dev: stop being a submodule

Now that x/website is Go 1.15-safe,
we can make go.dev a plain subdirectory
and use x/website's copy of the template packages
instead of the go.dev copy.

Change-Id: I55a1c3d47b6a96cedfd6eab260533d4e4b28ea88
Reviewed-on: https://go-review.googlesource.com/c/website/+/323893
Trust: Russ Cox <rsc@golang.org>
Reviewed-by: Jamal Carvalho <jamal@golang.org>
diff --git a/go.dev/cmd/internal/fmtsort/export_test.go b/go.dev/cmd/internal/fmtsort/export_test.go
deleted file mode 100644
index 25cbb5d..0000000
--- a/go.dev/cmd/internal/fmtsort/export_test.go
+++ /dev/null
@@ -1,11 +0,0 @@
-// Copyright 2018 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 fmtsort
-
-import "reflect"
-
-func Compare(a, b reflect.Value) int {
-	return compare(a, b)
-}
diff --git a/go.dev/cmd/internal/fmtsort/sort.go b/go.dev/cmd/internal/fmtsort/sort.go
deleted file mode 100644
index 7127ba6..0000000
--- a/go.dev/cmd/internal/fmtsort/sort.go
+++ /dev/null
@@ -1,220 +0,0 @@
-// Copyright 2018 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 fmtsort provides a general stable ordering mechanism
-// for maps, on behalf of the fmt and text/template packages.
-// It is not guaranteed to be efficient and works only for types
-// that are valid map keys.
-package fmtsort
-
-import (
-	"reflect"
-	"sort"
-)
-
-// Note: Throughout this package we avoid calling reflect.Value.Interface as
-// it is not always legal to do so and it's easier to avoid the issue than to face it.
-
-// SortedMap represents a map's keys and values. The keys and values are
-// aligned in index order: Value[i] is the value in the map corresponding to Key[i].
-type SortedMap struct {
-	Key   []reflect.Value
-	Value []reflect.Value
-}
-
-func (o *SortedMap) Len() int           { return len(o.Key) }
-func (o *SortedMap) Less(i, j int) bool { return compare(o.Key[i], o.Key[j]) < 0 }
-func (o *SortedMap) Swap(i, j int) {
-	o.Key[i], o.Key[j] = o.Key[j], o.Key[i]
-	o.Value[i], o.Value[j] = o.Value[j], o.Value[i]
-}
-
-// Sort accepts a map and returns a SortedMap that has the same keys and
-// values but in a stable sorted order according to the keys, modulo issues
-// raised by unorderable key values such as NaNs.
-//
-// The ordering rules are more general than with Go's < operator:
-//
-//  - when applicable, nil compares low
-//  - ints, floats, and strings order by <
-//  - NaN compares less than non-NaN floats
-//  - bool compares false before true
-//  - complex compares real, then imag
-//  - pointers compare by machine address
-//  - channel values compare by machine address
-//  - structs compare each field in turn
-//  - arrays compare each element in turn.
-//    Otherwise identical arrays compare by length.
-//  - interface values compare first by reflect.Type describing the concrete type
-//    and then by concrete value as described in the previous rules.
-//
-func Sort(mapValue reflect.Value) *SortedMap {
-	if mapValue.Type().Kind() != reflect.Map {
-		return nil
-	}
-	// Note: this code is arranged to not panic even in the presence
-	// of a concurrent map update. The runtime is responsible for
-	// yelling loudly if that happens. See issue 33275.
-	n := mapValue.Len()
-	key := make([]reflect.Value, 0, n)
-	value := make([]reflect.Value, 0, n)
-	iter := mapValue.MapRange()
-	for iter.Next() {
-		key = append(key, iter.Key())
-		value = append(value, iter.Value())
-	}
-	sorted := &SortedMap{
-		Key:   key,
-		Value: value,
-	}
-	sort.Stable(sorted)
-	return sorted
-}
-
-// compare compares two values of the same type. It returns -1, 0, 1
-// according to whether a > b (1), a == b (0), or a < b (-1).
-// If the types differ, it returns -1.
-// See the comment on Sort for the comparison rules.
-func compare(aVal, bVal reflect.Value) int {
-	aType, bType := aVal.Type(), bVal.Type()
-	if aType != bType {
-		return -1 // No good answer possible, but don't return 0: they're not equal.
-	}
-	switch aVal.Kind() {
-	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
-		a, b := aVal.Int(), bVal.Int()
-		switch {
-		case a < b:
-			return -1
-		case a > b:
-			return 1
-		default:
-			return 0
-		}
-	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
-		a, b := aVal.Uint(), bVal.Uint()
-		switch {
-		case a < b:
-			return -1
-		case a > b:
-			return 1
-		default:
-			return 0
-		}
-	case reflect.String:
-		a, b := aVal.String(), bVal.String()
-		switch {
-		case a < b:
-			return -1
-		case a > b:
-			return 1
-		default:
-			return 0
-		}
-	case reflect.Float32, reflect.Float64:
-		return floatCompare(aVal.Float(), bVal.Float())
-	case reflect.Complex64, reflect.Complex128:
-		a, b := aVal.Complex(), bVal.Complex()
-		if c := floatCompare(real(a), real(b)); c != 0 {
-			return c
-		}
-		return floatCompare(imag(a), imag(b))
-	case reflect.Bool:
-		a, b := aVal.Bool(), bVal.Bool()
-		switch {
-		case a == b:
-			return 0
-		case a:
-			return 1
-		default:
-			return -1
-		}
-	case reflect.Ptr, reflect.UnsafePointer:
-		a, b := aVal.Pointer(), bVal.Pointer()
-		switch {
-		case a < b:
-			return -1
-		case a > b:
-			return 1
-		default:
-			return 0
-		}
-	case reflect.Chan:
-		if c, ok := nilCompare(aVal, bVal); ok {
-			return c
-		}
-		ap, bp := aVal.Pointer(), bVal.Pointer()
-		switch {
-		case ap < bp:
-			return -1
-		case ap > bp:
-			return 1
-		default:
-			return 0
-		}
-	case reflect.Struct:
-		for i := 0; i < aVal.NumField(); i++ {
-			if c := compare(aVal.Field(i), bVal.Field(i)); c != 0 {
-				return c
-			}
-		}
-		return 0
-	case reflect.Array:
-		for i := 0; i < aVal.Len(); i++ {
-			if c := compare(aVal.Index(i), bVal.Index(i)); c != 0 {
-				return c
-			}
-		}
-		return 0
-	case reflect.Interface:
-		if c, ok := nilCompare(aVal, bVal); ok {
-			return c
-		}
-		c := compare(reflect.ValueOf(aVal.Elem().Type()), reflect.ValueOf(bVal.Elem().Type()))
-		if c != 0 {
-			return c
-		}
-		return compare(aVal.Elem(), bVal.Elem())
-	default:
-		// Certain types cannot appear as keys (maps, funcs, slices), but be explicit.
-		panic("bad type in compare: " + aType.String())
-	}
-}
-
-// nilCompare checks whether either value is nil. If not, the boolean is false.
-// If either value is nil, the boolean is true and the integer is the comparison
-// value. The comparison is defined to be 0 if both are nil, otherwise the one
-// nil value compares low. Both arguments must represent a chan, func,
-// interface, map, pointer, or slice.
-func nilCompare(aVal, bVal reflect.Value) (int, bool) {
-	if aVal.IsNil() {
-		if bVal.IsNil() {
-			return 0, true
-		}
-		return -1, true
-	}
-	if bVal.IsNil() {
-		return 1, true
-	}
-	return 0, false
-}
-
-// floatCompare compares two floating-point values. NaNs compare low.
-func floatCompare(a, b float64) int {
-	switch {
-	case isNaN(a):
-		return -1 // No good answer if b is a NaN so don't bother checking.
-	case isNaN(b):
-		return 1
-	case a < b:
-		return -1
-	case a > b:
-		return 1
-	}
-	return 0
-}
-
-func isNaN(a float64) bool {
-	return a != a
-}
diff --git a/go.dev/cmd/internal/fmtsort/sort_test.go b/go.dev/cmd/internal/fmtsort/sort_test.go
deleted file mode 100644
index 5c73fce..0000000
--- a/go.dev/cmd/internal/fmtsort/sort_test.go
+++ /dev/null
@@ -1,269 +0,0 @@
-// Copyright 2018 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 fmtsort_test
-
-import (
-	"fmt"
-	"math"
-	"reflect"
-	"strings"
-	"testing"
-	"unsafe"
-
-	"golang.org/x/website/go.dev/cmd/internal/fmtsort"
-)
-
-var compareTests = [][]reflect.Value{
-	ct(reflect.TypeOf(int(0)), -1, 0, 1),
-	ct(reflect.TypeOf(int8(0)), -1, 0, 1),
-	ct(reflect.TypeOf(int16(0)), -1, 0, 1),
-	ct(reflect.TypeOf(int32(0)), -1, 0, 1),
-	ct(reflect.TypeOf(int64(0)), -1, 0, 1),
-	ct(reflect.TypeOf(uint(0)), 0, 1, 5),
-	ct(reflect.TypeOf(uint8(0)), 0, 1, 5),
-	ct(reflect.TypeOf(uint16(0)), 0, 1, 5),
-	ct(reflect.TypeOf(uint32(0)), 0, 1, 5),
-	ct(reflect.TypeOf(uint64(0)), 0, 1, 5),
-	ct(reflect.TypeOf(uintptr(0)), 0, 1, 5),
-	ct(reflect.TypeOf(string("")), "", "a", "ab"),
-	ct(reflect.TypeOf(float32(0)), math.NaN(), math.Inf(-1), -1e10, 0, 1e10, math.Inf(1)),
-	ct(reflect.TypeOf(float64(0)), math.NaN(), math.Inf(-1), -1e10, 0, 1e10, math.Inf(1)),
-	ct(reflect.TypeOf(complex64(0+1i)), -1-1i, -1+0i, -1+1i, 0-1i, 0+0i, 0+1i, 1-1i, 1+0i, 1+1i),
-	ct(reflect.TypeOf(complex128(0+1i)), -1-1i, -1+0i, -1+1i, 0-1i, 0+0i, 0+1i, 1-1i, 1+0i, 1+1i),
-	ct(reflect.TypeOf(false), false, true),
-	ct(reflect.TypeOf(&ints[0]), &ints[0], &ints[1], &ints[2]),
-	ct(reflect.TypeOf(unsafe.Pointer(&ints[0])), unsafe.Pointer(&ints[0]), unsafe.Pointer(&ints[1]), unsafe.Pointer(&ints[2])),
-	ct(reflect.TypeOf(chans[0]), chans[0], chans[1], chans[2]),
-	ct(reflect.TypeOf(toy{}), toy{0, 1}, toy{0, 2}, toy{1, -1}, toy{1, 1}),
-	ct(reflect.TypeOf([2]int{}), [2]int{1, 1}, [2]int{1, 2}, [2]int{2, 0}),
-	ct(reflect.TypeOf(interface{}(interface{}(0))), iFace, 1, 2, 3),
-}
-
-var iFace interface{}
-
-func ct(typ reflect.Type, args ...interface{}) []reflect.Value {
-	value := make([]reflect.Value, len(args))
-	for i, v := range args {
-		x := reflect.ValueOf(v)
-		if !x.IsValid() { // Make it a typed nil.
-			x = reflect.Zero(typ)
-		} else {
-			x = x.Convert(typ)
-		}
-		value[i] = x
-	}
-	return value
-}
-
-func TestCompare(t *testing.T) {
-	for _, test := range compareTests {
-		for i, v0 := range test {
-			for j, v1 := range test {
-				c := fmtsort.Compare(v0, v1)
-				var expect int
-				switch {
-				case i == j:
-					expect = 0
-					// NaNs are tricky.
-					if typ := v0.Type(); (typ.Kind() == reflect.Float32 || typ.Kind() == reflect.Float64) && math.IsNaN(v0.Float()) {
-						expect = -1
-					}
-				case i < j:
-					expect = -1
-				case i > j:
-					expect = 1
-				}
-				if c != expect {
-					t.Errorf("%s: compare(%v,%v)=%d; expect %d", v0.Type(), v0, v1, c, expect)
-				}
-			}
-		}
-	}
-}
-
-type sortTest struct {
-	data  interface{} // Always a map.
-	print string      // Printed result using our custom printer.
-}
-
-var sortTests = []sortTest{
-	{
-		map[int]string{7: "bar", -3: "foo"},
-		"-3:foo 7:bar",
-	},
-	{
-		map[uint8]string{7: "bar", 3: "foo"},
-		"3:foo 7:bar",
-	},
-	{
-		map[string]string{"7": "bar", "3": "foo"},
-		"3:foo 7:bar",
-	},
-	{
-		map[float64]string{7: "bar", -3: "foo", math.NaN(): "nan", math.Inf(0): "inf"},
-		"NaN:nan -3:foo 7:bar +Inf:inf",
-	},
-	{
-		map[complex128]string{7 + 2i: "bar2", 7 + 1i: "bar", -3: "foo", complex(math.NaN(), 0i): "nan", complex(math.Inf(0), 0i): "inf"},
-		"(NaN+0i):nan (-3+0i):foo (7+1i):bar (7+2i):bar2 (+Inf+0i):inf",
-	},
-	{
-		map[bool]string{true: "true", false: "false"},
-		"false:false true:true",
-	},
-	{
-		chanMap(),
-		"CHAN0:0 CHAN1:1 CHAN2:2",
-	},
-	{
-		pointerMap(),
-		"PTR0:0 PTR1:1 PTR2:2",
-	},
-	{
-		unsafePointerMap(),
-		"UNSAFEPTR0:0 UNSAFEPTR1:1 UNSAFEPTR2:2",
-	},
-	{
-		map[toy]string{{7, 2}: "72", {7, 1}: "71", {3, 4}: "34"},
-		"{3 4}:34 {7 1}:71 {7 2}:72",
-	},
-	{
-		map[[2]int]string{{7, 2}: "72", {7, 1}: "71", {3, 4}: "34"},
-		"[3 4]:34 [7 1]:71 [7 2]:72",
-	},
-}
-
-func sprint(data interface{}) string {
-	om := fmtsort.Sort(reflect.ValueOf(data))
-	if om == nil {
-		return "nil"
-	}
-	b := new(strings.Builder)
-	for i, key := range om.Key {
-		if i > 0 {
-			b.WriteRune(' ')
-		}
-		b.WriteString(sprintKey(key))
-		b.WriteRune(':')
-		b.WriteString(fmt.Sprint(om.Value[i]))
-	}
-	return b.String()
-}
-
-// sprintKey formats a reflect.Value but gives reproducible values for some
-// problematic types such as pointers. Note that it only does special handling
-// for the troublesome types used in the test cases; it is not a general
-// printer.
-func sprintKey(key reflect.Value) string {
-	switch str := key.Type().String(); str {
-	case "*int":
-		ptr := key.Interface().(*int)
-		for i := range ints {
-			if ptr == &ints[i] {
-				return fmt.Sprintf("PTR%d", i)
-			}
-		}
-		return "PTR???"
-	case "unsafe.Pointer":
-		ptr := key.Interface().(unsafe.Pointer)
-		for i := range ints {
-			if ptr == unsafe.Pointer(&ints[i]) {
-				return fmt.Sprintf("UNSAFEPTR%d", i)
-			}
-		}
-		return "UNSAFEPTR???"
-	case "chan int":
-		c := key.Interface().(chan int)
-		for i := range chans {
-			if c == chans[i] {
-				return fmt.Sprintf("CHAN%d", i)
-			}
-		}
-		return "CHAN???"
-	default:
-		return fmt.Sprint(key)
-	}
-}
-
-var (
-	ints  [3]int
-	chans = [3]chan int{make(chan int), make(chan int), make(chan int)}
-)
-
-func pointerMap() map[*int]string {
-	m := make(map[*int]string)
-	for i := 2; i >= 0; i-- {
-		m[&ints[i]] = fmt.Sprint(i)
-	}
-	return m
-}
-
-func unsafePointerMap() map[unsafe.Pointer]string {
-	m := make(map[unsafe.Pointer]string)
-	for i := 2; i >= 0; i-- {
-		m[unsafe.Pointer(&ints[i])] = fmt.Sprint(i)
-	}
-	return m
-}
-
-func chanMap() map[chan int]string {
-	m := make(map[chan int]string)
-	for i := 2; i >= 0; i-- {
-		m[chans[i]] = fmt.Sprint(i)
-	}
-	return m
-}
-
-type toy struct {
-	A int // Exported.
-	b int // Unexported.
-}
-
-func TestOrder(t *testing.T) {
-	for _, test := range sortTests {
-		got := sprint(test.data)
-		if got != test.print {
-			t.Errorf("%s: got %q, want %q", reflect.TypeOf(test.data), got, test.print)
-		}
-	}
-}
-
-func TestInterface(t *testing.T) {
-	// A map containing multiple concrete types should be sorted by type,
-	// then value. However, the relative ordering of types is unspecified,
-	// so test this by checking the presence of sorted subgroups.
-	m := map[interface{}]string{
-		[2]int{1, 0}:             "",
-		[2]int{0, 1}:             "",
-		true:                     "",
-		false:                    "",
-		3.1:                      "",
-		2.1:                      "",
-		1.1:                      "",
-		math.NaN():               "",
-		3:                        "",
-		2:                        "",
-		1:                        "",
-		"c":                      "",
-		"b":                      "",
-		"a":                      "",
-		struct{ x, y int }{1, 0}: "",
-		struct{ x, y int }{0, 1}: "",
-	}
-	got := sprint(m)
-	typeGroups := []string{
-		"NaN: 1.1: 2.1: 3.1:", // float64
-		"false: true:",        // bool
-		"1: 2: 3:",            // int
-		"a: b: c:",            // string
-		"[0 1]: [1 0]:",       // [2]int
-		"{0 1}: {1 0}:",       // struct{ x int; y int }
-	}
-	for _, g := range typeGroups {
-		if !strings.Contains(got, g) {
-			t.Errorf("sorted map should contain %q", g)
-		}
-	}
-}
diff --git a/go.dev/cmd/internal/html/template/attr.go b/go.dev/cmd/internal/html/template/attr.go
deleted file mode 100644
index 22922e6..0000000
--- a/go.dev/cmd/internal/html/template/attr.go
+++ /dev/null
@@ -1,175 +0,0 @@
-// Copyright 2011 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 template
-
-import (
-	"strings"
-)
-
-// attrTypeMap[n] describes the value of the given attribute.
-// If an attribute affects (or can mask) the encoding or interpretation of
-// other content, or affects the contents, idempotency, or credentials of a
-// network message, then the value in this map is contentTypeUnsafe.
-// This map is derived from HTML5, specifically
-// https://www.w3.org/TR/html5/Overview.html#attributes-1
-// as well as "%URI"-typed attributes from
-// https://www.w3.org/TR/html4/index/attributes.html
-var attrTypeMap = map[string]contentType{
-	"accept":          contentTypePlain,
-	"accept-charset":  contentTypeUnsafe,
-	"action":          contentTypeURL,
-	"alt":             contentTypePlain,
-	"archive":         contentTypeURL,
-	"async":           contentTypeUnsafe,
-	"autocomplete":    contentTypePlain,
-	"autofocus":       contentTypePlain,
-	"autoplay":        contentTypePlain,
-	"background":      contentTypeURL,
-	"border":          contentTypePlain,
-	"checked":         contentTypePlain,
-	"cite":            contentTypeURL,
-	"challenge":       contentTypeUnsafe,
-	"charset":         contentTypeUnsafe,
-	"class":           contentTypePlain,
-	"classid":         contentTypeURL,
-	"codebase":        contentTypeURL,
-	"cols":            contentTypePlain,
-	"colspan":         contentTypePlain,
-	"content":         contentTypeUnsafe,
-	"contenteditable": contentTypePlain,
-	"contextmenu":     contentTypePlain,
-	"controls":        contentTypePlain,
-	"coords":          contentTypePlain,
-	"crossorigin":     contentTypeUnsafe,
-	"data":            contentTypeURL,
-	"datetime":        contentTypePlain,
-	"default":         contentTypePlain,
-	"defer":           contentTypeUnsafe,
-	"dir":             contentTypePlain,
-	"dirname":         contentTypePlain,
-	"disabled":        contentTypePlain,
-	"draggable":       contentTypePlain,
-	"dropzone":        contentTypePlain,
-	"enctype":         contentTypeUnsafe,
-	"for":             contentTypePlain,
-	"form":            contentTypeUnsafe,
-	"formaction":      contentTypeURL,
-	"formenctype":     contentTypeUnsafe,
-	"formmethod":      contentTypeUnsafe,
-	"formnovalidate":  contentTypeUnsafe,
-	"formtarget":      contentTypePlain,
-	"headers":         contentTypePlain,
-	"height":          contentTypePlain,
-	"hidden":          contentTypePlain,
-	"high":            contentTypePlain,
-	"href":            contentTypeURL,
-	"hreflang":        contentTypePlain,
-	"http-equiv":      contentTypeUnsafe,
-	"icon":            contentTypeURL,
-	"id":              contentTypePlain,
-	"ismap":           contentTypePlain,
-	"keytype":         contentTypeUnsafe,
-	"kind":            contentTypePlain,
-	"label":           contentTypePlain,
-	"lang":            contentTypePlain,
-	"language":        contentTypeUnsafe,
-	"list":            contentTypePlain,
-	"longdesc":        contentTypeURL,
-	"loop":            contentTypePlain,
-	"low":             contentTypePlain,
-	"manifest":        contentTypeURL,
-	"max":             contentTypePlain,
-	"maxlength":       contentTypePlain,
-	"media":           contentTypePlain,
-	"mediagroup":      contentTypePlain,
-	"method":          contentTypeUnsafe,
-	"min":             contentTypePlain,
-	"multiple":        contentTypePlain,
-	"name":            contentTypePlain,
-	"novalidate":      contentTypeUnsafe,
-	// Skip handler names from
-	// https://www.w3.org/TR/html5/webappapis.html#event-handlers-on-elements,-document-objects,-and-window-objects
-	// since we have special handling in attrType.
-	"open":        contentTypePlain,
-	"optimum":     contentTypePlain,
-	"pattern":     contentTypeUnsafe,
-	"placeholder": contentTypePlain,
-	"poster":      contentTypeURL,
-	"profile":     contentTypeURL,
-	"preload":     contentTypePlain,
-	"pubdate":     contentTypePlain,
-	"radiogroup":  contentTypePlain,
-	"readonly":    contentTypePlain,
-	"rel":         contentTypeUnsafe,
-	"required":    contentTypePlain,
-	"reversed":    contentTypePlain,
-	"rows":        contentTypePlain,
-	"rowspan":     contentTypePlain,
-	"sandbox":     contentTypeUnsafe,
-	"spellcheck":  contentTypePlain,
-	"scope":       contentTypePlain,
-	"scoped":      contentTypePlain,
-	"seamless":    contentTypePlain,
-	"selected":    contentTypePlain,
-	"shape":       contentTypePlain,
-	"size":        contentTypePlain,
-	"sizes":       contentTypePlain,
-	"span":        contentTypePlain,
-	"src":         contentTypeURL,
-	"srcdoc":      contentTypeHTML,
-	"srclang":     contentTypePlain,
-	"srcset":      contentTypeSrcset,
-	"start":       contentTypePlain,
-	"step":        contentTypePlain,
-	"style":       contentTypeCSS,
-	"tabindex":    contentTypePlain,
-	"target":      contentTypePlain,
-	"title":       contentTypePlain,
-	"type":        contentTypeUnsafe,
-	"usemap":      contentTypeURL,
-	"value":       contentTypeUnsafe,
-	"width":       contentTypePlain,
-	"wrap":        contentTypePlain,
-	"xmlns":       contentTypeURL,
-}
-
-// attrType returns a conservative (upper-bound on authority) guess at the
-// type of the lowercase named attribute.
-func attrType(name string) contentType {
-	if strings.HasPrefix(name, "data-") {
-		// Strip data- so that custom attribute heuristics below are
-		// widely applied.
-		// Treat data-action as URL below.
-		name = name[5:]
-	} else if colon := strings.IndexRune(name, ':'); colon != -1 {
-		if name[:colon] == "xmlns" {
-			return contentTypeURL
-		}
-		// Treat svg:href and xlink:href as href below.
-		name = name[colon+1:]
-	}
-	if t, ok := attrTypeMap[name]; ok {
-		return t
-	}
-	// Treat partial event handler names as script.
-	if strings.HasPrefix(name, "on") {
-		return contentTypeJS
-	}
-
-	// Heuristics to prevent "javascript:..." injection in custom
-	// data attributes and custom attributes like g:tweetUrl.
-	// https://www.w3.org/TR/html5/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes
-	// "Custom data attributes are intended to store custom data
-	//  private to the page or application, for which there are no
-	//  more appropriate attributes or elements."
-	// Developers seem to store URL content in data URLs that start
-	// or end with "URI" or "URL".
-	if strings.Contains(name, "src") ||
-		strings.Contains(name, "uri") ||
-		strings.Contains(name, "url") {
-		return contentTypeURL
-	}
-	return contentTypePlain
-}
diff --git a/go.dev/cmd/internal/html/template/attr_string.go b/go.dev/cmd/internal/html/template/attr_string.go
deleted file mode 100644
index babe70c..0000000
--- a/go.dev/cmd/internal/html/template/attr_string.go
+++ /dev/null
@@ -1,16 +0,0 @@
-// Code generated by "stringer -type attr"; DO NOT EDIT.
-
-package template
-
-import "strconv"
-
-const _attr_name = "attrNoneattrScriptattrScriptTypeattrStyleattrURLattrSrcset"
-
-var _attr_index = [...]uint8{0, 8, 18, 32, 41, 48, 58}
-
-func (i attr) String() string {
-	if i >= attr(len(_attr_index)-1) {
-		return "attr(" + strconv.FormatInt(int64(i), 10) + ")"
-	}
-	return _attr_name[_attr_index[i]:_attr_index[i+1]]
-}
diff --git a/go.dev/cmd/internal/html/template/clone_test.go b/go.dev/cmd/internal/html/template/clone_test.go
deleted file mode 100644
index c42d241..0000000
--- a/go.dev/cmd/internal/html/template/clone_test.go
+++ /dev/null
@@ -1,280 +0,0 @@
-// Copyright 2011 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 template
-
-import (
-	"bytes"
-	"errors"
-	"fmt"
-	"io/ioutil"
-	"strings"
-	"sync"
-	"testing"
-
-	"golang.org/x/website/go.dev/cmd/internal/text/template/parse"
-)
-
-func TestAddParseTreeHTML(t *testing.T) {
-	root := Must(New("root").Parse(`{{define "a"}} {{.}} {{template "b"}} {{.}} "></a>{{end}}`))
-	tree, err := parse.Parse("t", `{{define "b"}}<a href="{{end}}`, "", "", nil, nil)
-	if err != nil {
-		t.Fatal(err)
-	}
-	added := Must(root.AddParseTree("b", tree["b"]))
-	b := new(bytes.Buffer)
-	err = added.ExecuteTemplate(b, "a", "1>0")
-	if err != nil {
-		t.Fatal(err)
-	}
-	if got, want := b.String(), ` 1&gt;0 <a href=" 1%3e0 "></a>`; got != want {
-		t.Errorf("got %q want %q", got, want)
-	}
-}
-
-func TestClone(t *testing.T) {
-	// The {{.}} will be executed with data "<i>*/" in different contexts.
-	// In the t0 template, it will be in a text context.
-	// In the t1 template, it will be in a URL context.
-	// In the t2 template, it will be in a JavaScript context.
-	// In the t3 template, it will be in a CSS context.
-	const tmpl = `{{define "a"}}{{template "lhs"}}{{.}}{{template "rhs"}}{{end}}`
-	b := new(bytes.Buffer)
-
-	// Create an incomplete template t0.
-	t0 := Must(New("t0").Parse(tmpl))
-
-	// Clone t0 as t1.
-	t1 := Must(t0.Clone())
-	Must(t1.Parse(`{{define "lhs"}} <a href=" {{end}}`))
-	Must(t1.Parse(`{{define "rhs"}} "></a> {{end}}`))
-
-	// Execute t1.
-	b.Reset()
-	if err := t1.ExecuteTemplate(b, "a", "<i>*/"); err != nil {
-		t.Fatal(err)
-	}
-	if got, want := b.String(), ` <a href=" %3ci%3e*/ "></a> `; got != want {
-		t.Errorf("t1: got %q want %q", got, want)
-	}
-
-	// Clone t0 as t2.
-	t2 := Must(t0.Clone())
-	Must(t2.Parse(`{{define "lhs"}} <p onclick="javascript: {{end}}`))
-	Must(t2.Parse(`{{define "rhs"}} "></p> {{end}}`))
-
-	// Execute t2.
-	b.Reset()
-	if err := t2.ExecuteTemplate(b, "a", "<i>*/"); err != nil {
-		t.Fatal(err)
-	}
-	if got, want := b.String(), ` <p onclick="javascript: &#34;\u003ci\u003e*/&#34; "></p> `; got != want {
-		t.Errorf("t2: got %q want %q", got, want)
-	}
-
-	// Clone t0 as t3, but do not execute t3 yet.
-	t3 := Must(t0.Clone())
-	Must(t3.Parse(`{{define "lhs"}} <style> {{end}}`))
-	Must(t3.Parse(`{{define "rhs"}} </style> {{end}}`))
-
-	// Complete t0.
-	Must(t0.Parse(`{{define "lhs"}} ( {{end}}`))
-	Must(t0.Parse(`{{define "rhs"}} ) {{end}}`))
-
-	// Clone t0 as t4. Redefining the "lhs" template should not fail.
-	t4 := Must(t0.Clone())
-	if _, err := t4.Parse(`{{define "lhs"}} OK {{end}}`); err != nil {
-		t.Errorf(`redefine "lhs": got err %v want nil`, err)
-	}
-	// Cloning t1 should fail as it has been executed.
-	if _, err := t1.Clone(); err == nil {
-		t.Error("cloning t1: got nil err want non-nil")
-	}
-	// Redefining the "lhs" template in t1 should fail as it has been executed.
-	if _, err := t1.Parse(`{{define "lhs"}} OK {{end}}`); err == nil {
-		t.Error(`redefine "lhs": got nil err want non-nil`)
-	}
-
-	// Execute t0.
-	b.Reset()
-	if err := t0.ExecuteTemplate(b, "a", "<i>*/"); err != nil {
-		t.Fatal(err)
-	}
-	if got, want := b.String(), ` ( &lt;i&gt;*/ ) `; got != want {
-		t.Errorf("t0: got %q want %q", got, want)
-	}
-
-	// Clone t0. This should fail, as t0 has already executed.
-	if _, err := t0.Clone(); err == nil {
-		t.Error(`t0.Clone(): got nil err want non-nil`)
-	}
-
-	// Similarly, cloning sub-templates should fail.
-	if _, err := t0.Lookup("a").Clone(); err == nil {
-		t.Error(`t0.Lookup("a").Clone(): got nil err want non-nil`)
-	}
-	if _, err := t0.Lookup("lhs").Clone(); err == nil {
-		t.Error(`t0.Lookup("lhs").Clone(): got nil err want non-nil`)
-	}
-
-	// Execute t3.
-	b.Reset()
-	if err := t3.ExecuteTemplate(b, "a", "<i>*/"); err != nil {
-		t.Fatal(err)
-	}
-	if got, want := b.String(), ` <style> ZgotmplZ </style> `; got != want {
-		t.Errorf("t3: got %q want %q", got, want)
-	}
-}
-
-func TestTemplates(t *testing.T) {
-	names := []string{"t0", "a", "lhs", "rhs"}
-	// Some template definitions borrowed from TestClone.
-	const tmpl = `
-		{{define "a"}}{{template "lhs"}}{{.}}{{template "rhs"}}{{end}}
-		{{define "lhs"}} <a href=" {{end}}
-		{{define "rhs"}} "></a> {{end}}`
-	t0 := Must(New("t0").Parse(tmpl))
-	templates := t0.Templates()
-	if len(templates) != len(names) {
-		t.Errorf("expected %d templates; got %d", len(names), len(templates))
-	}
-	for _, name := range names {
-		found := false
-		for _, tmpl := range templates {
-			if name == tmpl.text.Name() {
-				found = true
-				break
-			}
-		}
-		if !found {
-			t.Error("could not find template", name)
-		}
-	}
-}
-
-// This used to crash; https://golang.org/issue/3281
-func TestCloneCrash(t *testing.T) {
-	t1 := New("all")
-	Must(t1.New("t1").Parse(`{{define "foo"}}foo{{end}}`))
-	t1.Clone()
-}
-
-// Ensure that this guarantee from the docs is upheld:
-// "Further calls to Parse in the copy will add templates
-// to the copy but not to the original."
-func TestCloneThenParse(t *testing.T) {
-	t0 := Must(New("t0").Parse(`{{define "a"}}{{template "embedded"}}{{end}}`))
-	t1 := Must(t0.Clone())
-	Must(t1.Parse(`{{define "embedded"}}t1{{end}}`))
-	if len(t0.Templates())+1 != len(t1.Templates()) {
-		t.Error("adding a template to a clone added it to the original")
-	}
-	// double check that the embedded template isn't available in the original
-	err := t0.ExecuteTemplate(ioutil.Discard, "a", nil)
-	if err == nil {
-		t.Error("expected 'no such template' error")
-	}
-}
-
-// https://golang.org/issue/5980
-func TestFuncMapWorksAfterClone(t *testing.T) {
-	funcs := FuncMap{"customFunc": func() (string, error) {
-		return "", errors.New("issue5980")
-	}}
-
-	// get the expected error output (no clone)
-	uncloned := Must(New("").Funcs(funcs).Parse("{{customFunc}}"))
-	wantErr := uncloned.Execute(ioutil.Discard, nil)
-
-	// toClone must be the same as uncloned. It has to be recreated from scratch,
-	// since cloning cannot occur after execution.
-	toClone := Must(New("").Funcs(funcs).Parse("{{customFunc}}"))
-	cloned := Must(toClone.Clone())
-	gotErr := cloned.Execute(ioutil.Discard, nil)
-
-	if wantErr.Error() != gotErr.Error() {
-		t.Errorf("clone error message mismatch want %q got %q", wantErr, gotErr)
-	}
-}
-
-// https://golang.org/issue/16101
-func TestTemplateCloneExecuteRace(t *testing.T) {
-	const (
-		input   = `<title>{{block "a" .}}a{{end}}</title><body>{{block "b" .}}b{{end}}<body>`
-		overlay = `{{define "b"}}A{{end}}`
-	)
-	outer := Must(New("outer").Parse(input))
-	tmpl := Must(Must(outer.Clone()).Parse(overlay))
-
-	var wg sync.WaitGroup
-	for i := 0; i < 10; i++ {
-		wg.Add(1)
-		go func() {
-			defer wg.Done()
-			for i := 0; i < 100; i++ {
-				if err := tmpl.Execute(ioutil.Discard, "data"); err != nil {
-					panic(err)
-				}
-			}
-		}()
-	}
-	wg.Wait()
-}
-
-func TestTemplateCloneLookup(t *testing.T) {
-	// Template.escape makes an assumption that the template associated
-	// with t.Name() is t. Check that this holds.
-	tmpl := Must(New("x").Parse("a"))
-	tmpl = Must(tmpl.Clone())
-	if tmpl.Lookup(tmpl.Name()) != tmpl {
-		t.Error("after Clone, tmpl.Lookup(tmpl.Name()) != tmpl")
-	}
-}
-
-func TestCloneGrowth(t *testing.T) {
-	tmpl := Must(New("root").Parse(`<title>{{block "B". }}Arg{{end}}</title>`))
-	tmpl = Must(tmpl.Clone())
-	Must(tmpl.Parse(`{{define "B"}}Text{{end}}`))
-	for i := 0; i < 10; i++ {
-		tmpl.Execute(ioutil.Discard, nil)
-	}
-	if len(tmpl.DefinedTemplates()) > 200 {
-		t.Fatalf("too many templates: %v", len(tmpl.DefinedTemplates()))
-	}
-}
-
-// https://golang.org/issue/17735
-func TestCloneRedefinedName(t *testing.T) {
-	const base = `
-{{ define "a" -}}<title>{{ template "b" . -}}</title>{{ end -}}
-{{ define "b" }}{{ end -}}
-`
-	const page = `{{ template "a" . }}`
-
-	t1 := Must(New("a").Parse(base))
-
-	for i := 0; i < 2; i++ {
-		t2 := Must(t1.Clone())
-		t2 = Must(t2.New(fmt.Sprintf("%d", i)).Parse(page))
-		err := t2.Execute(ioutil.Discard, nil)
-		if err != nil {
-			t.Fatal(err)
-		}
-	}
-}
-
-// Issue 24791.
-func TestClonePipe(t *testing.T) {
-	a := Must(New("a").Parse(`{{define "a"}}{{range $v := .A}}{{$v}}{{end}}{{end}}`))
-	data := struct{ A []string }{A: []string{"hi"}}
-	b := Must(a.Clone())
-	var buf strings.Builder
-	if err := b.Execute(&buf, &data); err != nil {
-		t.Fatal(err)
-	}
-	if got, want := buf.String(), "hi"; got != want {
-		t.Errorf("got %q want %q", got, want)
-	}
-}
diff --git a/go.dev/cmd/internal/html/template/content.go b/go.dev/cmd/internal/html/template/content.go
deleted file mode 100644
index 6ba87a9..0000000
--- a/go.dev/cmd/internal/html/template/content.go
+++ /dev/null
@@ -1,185 +0,0 @@
-// Copyright 2011 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 template
-
-import (
-	"fmt"
-	"reflect"
-)
-
-// Strings of content from a trusted source.
-type (
-	// CSS encapsulates known safe content that matches any of:
-	//   1. The CSS3 stylesheet production, such as `p { color: purple }`.
-	//   2. The CSS3 rule production, such as `a[href=~"https:"].foo#bar`.
-	//   3. CSS3 declaration productions, such as `color: red; margin: 2px`.
-	//   4. The CSS3 value production, such as `rgba(0, 0, 255, 127)`.
-	// See https://www.w3.org/TR/css3-syntax/#parsing and
-	// https://web.archive.org/web/20090211114933/http://w3.org/TR/css3-syntax#style
-	//
-	// Use of this type presents a security risk:
-	// the encapsulated content should come from a trusted source,
-	// as it will be included verbatim in the template output.
-	CSS string
-
-	// HTML encapsulates a known safe HTML document fragment.
-	// It should not be used for HTML from a third-party, or HTML with
-	// unclosed tags or comments. The outputs of a sound HTML sanitizer
-	// and a template escaped by this package are fine for use with HTML.
-	//
-	// Use of this type presents a security risk:
-	// the encapsulated content should come from a trusted source,
-	// as it will be included verbatim in the template output.
-	HTML string
-
-	// HTMLAttr encapsulates an HTML attribute from a trusted source,
-	// for example, ` dir="ltr"`.
-	//
-	// Use of this type presents a security risk:
-	// the encapsulated content should come from a trusted source,
-	// as it will be included verbatim in the template output.
-	HTMLAttr string
-
-	// JS encapsulates a known safe EcmaScript5 Expression, for example,
-	// `(x + y * z())`.
-	// Template authors are responsible for ensuring that typed expressions
-	// do not break the intended precedence and that there is no
-	// statement/expression ambiguity as when passing an expression like
-	// "{ foo: bar() }\n['foo']()", which is both a valid Expression and a
-	// valid Program with a very different meaning.
-	//
-	// Use of this type presents a security risk:
-	// the encapsulated content should come from a trusted source,
-	// as it will be included verbatim in the template output.
-	//
-	// Using JS to include valid but untrusted JSON is not safe.
-	// A safe alternative is to parse the JSON with json.Unmarshal and then
-	// pass the resultant object into the template, where it will be
-	// converted to sanitized JSON when presented in a JavaScript context.
-	JS string
-
-	// JSStr encapsulates a sequence of characters meant to be embedded
-	// between quotes in a JavaScript expression.
-	// The string must match a series of StringCharacters:
-	//   StringCharacter :: SourceCharacter but not `\` or LineTerminator
-	//                    | EscapeSequence
-	// Note that LineContinuations are not allowed.
-	// JSStr("foo\\nbar") is fine, but JSStr("foo\\\nbar") is not.
-	//
-	// Use of this type presents a security risk:
-	// the encapsulated content should come from a trusted source,
-	// as it will be included verbatim in the template output.
-	JSStr string
-
-	// URL encapsulates a known safe URL or URL substring (see RFC 3986).
-	// A URL like `javascript:checkThatFormNotEditedBeforeLeavingPage()`
-	// from a trusted source should go in the page, but by default dynamic
-	// `javascript:` URLs are filtered out since they are a frequently
-	// exploited injection vector.
-	//
-	// Use of this type presents a security risk:
-	// the encapsulated content should come from a trusted source,
-	// as it will be included verbatim in the template output.
-	URL string
-
-	// Srcset encapsulates a known safe srcset attribute
-	// (see https://w3c.github.io/html/semantics-embedded-content.html#element-attrdef-img-srcset).
-	//
-	// Use of this type presents a security risk:
-	// the encapsulated content should come from a trusted source,
-	// as it will be included verbatim in the template output.
-	Srcset string
-)
-
-type contentType uint8
-
-const (
-	contentTypePlain contentType = iota
-	contentTypeCSS
-	contentTypeHTML
-	contentTypeHTMLAttr
-	contentTypeJS
-	contentTypeJSStr
-	contentTypeURL
-	contentTypeSrcset
-	// contentTypeUnsafe is used in attr.go for values that affect how
-	// embedded content and network messages are formed, vetted,
-	// or interpreted; or which credentials network messages carry.
-	contentTypeUnsafe
-)
-
-// indirect returns the value, after dereferencing as many times
-// as necessary to reach the base type (or nil).
-func indirect(a interface{}) interface{} {
-	if a == nil {
-		return nil
-	}
-	if t := reflect.TypeOf(a); t.Kind() != reflect.Ptr {
-		// Avoid creating a reflect.Value if it's not a pointer.
-		return a
-	}
-	v := reflect.ValueOf(a)
-	for v.Kind() == reflect.Ptr && !v.IsNil() {
-		v = v.Elem()
-	}
-	return v.Interface()
-}
-
-var (
-	errorType       = reflect.TypeOf((*error)(nil)).Elem()
-	fmtStringerType = reflect.TypeOf((*fmt.Stringer)(nil)).Elem()
-)
-
-// indirectToStringerOrError returns the value, after dereferencing as many times
-// as necessary to reach the base type (or nil) or an implementation of fmt.Stringer
-// or error,
-func indirectToStringerOrError(a interface{}) interface{} {
-	if a == nil {
-		return nil
-	}
-	v := reflect.ValueOf(a)
-	for !v.Type().Implements(fmtStringerType) && !v.Type().Implements(errorType) && v.Kind() == reflect.Ptr && !v.IsNil() {
-		v = v.Elem()
-	}
-	return v.Interface()
-}
-
-// stringify converts its arguments to a string and the type of the content.
-// All pointers are dereferenced, as in the text/template package.
-func stringify(args ...interface{}) (string, contentType) {
-	if len(args) == 1 {
-		switch s := indirect(args[0]).(type) {
-		case string:
-			return s, contentTypePlain
-		case CSS:
-			return string(s), contentTypeCSS
-		case HTML:
-			return string(s), contentTypeHTML
-		case HTMLAttr:
-			return string(s), contentTypeHTMLAttr
-		case JS:
-			return string(s), contentTypeJS
-		case JSStr:
-			return string(s), contentTypeJSStr
-		case URL:
-			return string(s), contentTypeURL
-		case Srcset:
-			return string(s), contentTypeSrcset
-		}
-	}
-	i := 0
-	for _, arg := range args {
-		// We skip untyped nil arguments for backward compatibility.
-		// Without this they would be output as <nil>, escaped.
-		// See issue 25875.
-		if arg == nil {
-			continue
-		}
-
-		args[i] = indirectToStringerOrError(arg)
-		i++
-	}
-	return fmt.Sprint(args[:i]...), contentTypePlain
-}
diff --git a/go.dev/cmd/internal/html/template/content_test.go b/go.dev/cmd/internal/html/template/content_test.go
deleted file mode 100644
index 70cbd4e..0000000
--- a/go.dev/cmd/internal/html/template/content_test.go
+++ /dev/null
@@ -1,458 +0,0 @@
-// Copyright 2011 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 template
-
-import (
-	"bytes"
-	"fmt"
-	"strings"
-	"testing"
-)
-
-func TestTypedContent(t *testing.T) {
-	data := []interface{}{
-		`<b> "foo%" O'Reilly &bar;`,
-		CSS(`a[href =~ "//example.com"]#foo`),
-		HTML(`Hello, <b>World</b> &amp;tc!`),
-		HTMLAttr(` dir="ltr"`),
-		JS(`c && alert("Hello, World!");`),
-		JSStr(`Hello, World & O'Reilly\u0021`),
-		URL(`greeting=H%69,&addressee=(World)`),
-		Srcset(`greeting=H%69,&addressee=(World) 2x, https://golang.org/favicon.ico 500.5w`),
-		URL(`,foo/,`),
-	}
-
-	// For each content sensitive escaper, see how it does on
-	// each of the typed strings above.
-	tests := []struct {
-		// A template containing a single {{.}}.
-		input string
-		want  []string
-	}{
-		{
-			`<style>{{.}} { color: blue }</style>`,
-			[]string{
-				`ZgotmplZ`,
-				// Allowed but not escaped.
-				`a[href =~ "//example.com"]#foo`,
-				`ZgotmplZ`,
-				`ZgotmplZ`,
-				`ZgotmplZ`,
-				`ZgotmplZ`,
-				`ZgotmplZ`,
-				`ZgotmplZ`,
-				`ZgotmplZ`,
-			},
-		},
-		{
-			`<div style="{{.}}">`,
-			[]string{
-				`ZgotmplZ`,
-				// Allowed and HTML escaped.
-				`a[href =~ &#34;//example.com&#34;]#foo`,
-				`ZgotmplZ`,
-				`ZgotmplZ`,
-				`ZgotmplZ`,
-				`ZgotmplZ`,
-				`ZgotmplZ`,
-				`ZgotmplZ`,
-				`ZgotmplZ`,
-			},
-		},
-		{
-			`{{.}}`,
-			[]string{
-				`&lt;b&gt; &#34;foo%&#34; O&#39;Reilly &amp;bar;`,
-				`a[href =~ &#34;//example.com&#34;]#foo`,
-				// Not escaped.
-				`Hello, <b>World</b> &amp;tc!`,
-				` dir=&#34;ltr&#34;`,
-				`c &amp;&amp; alert(&#34;Hello, World!&#34;);`,
-				`Hello, World &amp; O&#39;Reilly\u0021`,
-				`greeting=H%69,&amp;addressee=(World)`,
-				`greeting=H%69,&amp;addressee=(World) 2x, https://golang.org/favicon.ico 500.5w`,
-				`,foo/,`,
-			},
-		},
-		{
-			`<a{{.}}>`,
-			[]string{
-				`ZgotmplZ`,
-				`ZgotmplZ`,
-				`ZgotmplZ`,
-				// Allowed and HTML escaped.
-				` dir="ltr"`,
-				`ZgotmplZ`,
-				`ZgotmplZ`,
-				`ZgotmplZ`,
-				`ZgotmplZ`,
-				`ZgotmplZ`,
-			},
-		},
-		{
-			`<a title={{.}}>`,
-			[]string{
-				`&lt;b&gt;&#32;&#34;foo%&#34;&#32;O&#39;Reilly&#32;&amp;bar;`,
-				`a[href&#32;&#61;~&#32;&#34;//example.com&#34;]#foo`,
-				// Tags stripped, spaces escaped, entity not re-escaped.
-				`Hello,&#32;World&#32;&amp;tc!`,
-				`&#32;dir&#61;&#34;ltr&#34;`,
-				`c&#32;&amp;&amp;&#32;alert(&#34;Hello,&#32;World!&#34;);`,
-				`Hello,&#32;World&#32;&amp;&#32;O&#39;Reilly\u0021`,
-				`greeting&#61;H%69,&amp;addressee&#61;(World)`,
-				`greeting&#61;H%69,&amp;addressee&#61;(World)&#32;2x,&#32;https://golang.org/favicon.ico&#32;500.5w`,
-				`,foo/,`,
-			},
-		},
-		{
-			`<a title='{{.}}'>`,
-			[]string{
-				`&lt;b&gt; &#34;foo%&#34; O&#39;Reilly &amp;bar;`,
-				`a[href =~ &#34;//example.com&#34;]#foo`,
-				// Tags stripped, entity not re-escaped.
-				`Hello, World &amp;tc!`,
-				` dir=&#34;ltr&#34;`,
-				`c &amp;&amp; alert(&#34;Hello, World!&#34;);`,
-				`Hello, World &amp; O&#39;Reilly\u0021`,
-				`greeting=H%69,&amp;addressee=(World)`,
-				`greeting=H%69,&amp;addressee=(World) 2x, https://golang.org/favicon.ico 500.5w`,
-				`,foo/,`,
-			},
-		},
-		{
-			`<textarea>{{.}}</textarea>`,
-			[]string{
-				`&lt;b&gt; &#34;foo%&#34; O&#39;Reilly &amp;bar;`,
-				`a[href =~ &#34;//example.com&#34;]#foo`,
-				// Angle brackets escaped to prevent injection of close tags, entity not re-escaped.
-				`Hello, &lt;b&gt;World&lt;/b&gt; &amp;tc!`,
-				` dir=&#34;ltr&#34;`,
-				`c &amp;&amp; alert(&#34;Hello, World!&#34;);`,
-				`Hello, World &amp; O&#39;Reilly\u0021`,
-				`greeting=H%69,&amp;addressee=(World)`,
-				`greeting=H%69,&amp;addressee=(World) 2x, https://golang.org/favicon.ico 500.5w`,
-				`,foo/,`,
-			},
-		},
-		{
-			`<script>alert({{.}})</script>`,
-			[]string{
-				`"\u003cb\u003e \"foo%\" O'Reilly \u0026bar;"`,
-				`"a[href =~ \"//example.com\"]#foo"`,
-				`"Hello, \u003cb\u003eWorld\u003c/b\u003e \u0026amp;tc!"`,
-				`" dir=\"ltr\""`,
-				// Not escaped.
-				`c && alert("Hello, World!");`,
-				// Escape sequence not over-escaped.
-				`"Hello, World & O'Reilly\u0021"`,
-				`"greeting=H%69,\u0026addressee=(World)"`,
-				`"greeting=H%69,\u0026addressee=(World) 2x, https://golang.org/favicon.ico 500.5w"`,
-				`",foo/,"`,
-			},
-		},
-		{
-			`<button onclick="alert({{.}})">`,
-			[]string{
-				`&#34;\u003cb\u003e \&#34;foo%\&#34; O&#39;Reilly \u0026bar;&#34;`,
-				`&#34;a[href =~ \&#34;//example.com\&#34;]#foo&#34;`,
-				`&#34;Hello, \u003cb\u003eWorld\u003c/b\u003e \u0026amp;tc!&#34;`,
-				`&#34; dir=\&#34;ltr\&#34;&#34;`,
-				// Not JS escaped but HTML escaped.
-				`c &amp;&amp; alert(&#34;Hello, World!&#34;);`,
-				// Escape sequence not over-escaped.
-				`&#34;Hello, World &amp; O&#39;Reilly\u0021&#34;`,
-				`&#34;greeting=H%69,\u0026addressee=(World)&#34;`,
-				`&#34;greeting=H%69,\u0026addressee=(World) 2x, https://golang.org/favicon.ico 500.5w&#34;`,
-				`&#34;,foo/,&#34;`,
-			},
-		},
-		{
-			`<script>alert("{{.}}")</script>`,
-			[]string{
-				`\u003cb\u003e \u0022foo%\u0022 O\u0027Reilly \u0026bar;`,
-				`a[href =~ \u0022\/\/example.com\u0022]#foo`,
-				`Hello, \u003cb\u003eWorld\u003c\/b\u003e \u0026amp;tc!`,
-				` dir=\u0022ltr\u0022`,
-				`c \u0026\u0026 alert(\u0022Hello, World!\u0022);`,
-				// Escape sequence not over-escaped.
-				`Hello, World \u0026 O\u0027Reilly\u0021`,
-				`greeting=H%69,\u0026addressee=(World)`,
-				`greeting=H%69,\u0026addressee=(World) 2x, https:\/\/golang.org\/favicon.ico 500.5w`,
-				`,foo\/,`,
-			},
-		},
-		{
-			`<script type="text/javascript">alert("{{.}}")</script>`,
-			[]string{
-				`\u003cb\u003e \u0022foo%\u0022 O\u0027Reilly \u0026bar;`,
-				`a[href =~ \u0022\/\/example.com\u0022]#foo`,
-				`Hello, \u003cb\u003eWorld\u003c\/b\u003e \u0026amp;tc!`,
-				` dir=\u0022ltr\u0022`,
-				`c \u0026\u0026 alert(\u0022Hello, World!\u0022);`,
-				// Escape sequence not over-escaped.
-				`Hello, World \u0026 O\u0027Reilly\u0021`,
-				`greeting=H%69,\u0026addressee=(World)`,
-				`greeting=H%69,\u0026addressee=(World) 2x, https:\/\/golang.org\/favicon.ico 500.5w`,
-				`,foo\/,`,
-			},
-		},
-		{
-			`<script type="text/javascript">alert({{.}})</script>`,
-			[]string{
-				`"\u003cb\u003e \"foo%\" O'Reilly \u0026bar;"`,
-				`"a[href =~ \"//example.com\"]#foo"`,
-				`"Hello, \u003cb\u003eWorld\u003c/b\u003e \u0026amp;tc!"`,
-				`" dir=\"ltr\""`,
-				// Not escaped.
-				`c && alert("Hello, World!");`,
-				// Escape sequence not over-escaped.
-				`"Hello, World & O'Reilly\u0021"`,
-				`"greeting=H%69,\u0026addressee=(World)"`,
-				`"greeting=H%69,\u0026addressee=(World) 2x, https://golang.org/favicon.ico 500.5w"`,
-				`",foo/,"`,
-			},
-		},
-		{
-			// Not treated as JS. The output is same as for <div>{{.}}</div>
-			`<script type="golang.org/x/website/go.dev/cmd/internal/text/template">{{.}}</script>`,
-			[]string{
-				`&lt;b&gt; &#34;foo%&#34; O&#39;Reilly &amp;bar;`,
-				`a[href =~ &#34;//example.com&#34;]#foo`,
-				// Not escaped.
-				`Hello, <b>World</b> &amp;tc!`,
-				` dir=&#34;ltr&#34;`,
-				`c &amp;&amp; alert(&#34;Hello, World!&#34;);`,
-				`Hello, World &amp; O&#39;Reilly\u0021`,
-				`greeting=H%69,&amp;addressee=(World)`,
-				`greeting=H%69,&amp;addressee=(World) 2x, https://golang.org/favicon.ico 500.5w`,
-				`,foo/,`,
-			},
-		},
-		{
-			`<button onclick='alert("{{.}}")'>`,
-			[]string{
-				`\u003cb\u003e \u0022foo%\u0022 O\u0027Reilly \u0026bar;`,
-				`a[href =~ \u0022\/\/example.com\u0022]#foo`,
-				`Hello, \u003cb\u003eWorld\u003c\/b\u003e \u0026amp;tc!`,
-				` dir=\u0022ltr\u0022`,
-				`c \u0026\u0026 alert(\u0022Hello, World!\u0022);`,
-				// Escape sequence not over-escaped.
-				`Hello, World \u0026 O\u0027Reilly\u0021`,
-				`greeting=H%69,\u0026addressee=(World)`,
-				`greeting=H%69,\u0026addressee=(World) 2x, https:\/\/golang.org\/favicon.ico 500.5w`,
-				`,foo\/,`,
-			},
-		},
-		{
-			`<a href="?q={{.}}">`,
-			[]string{
-				`%3cb%3e%20%22foo%25%22%20O%27Reilly%20%26bar%3b`,
-				`a%5bhref%20%3d~%20%22%2f%2fexample.com%22%5d%23foo`,
-				`Hello%2c%20%3cb%3eWorld%3c%2fb%3e%20%26amp%3btc%21`,
-				`%20dir%3d%22ltr%22`,
-				`c%20%26%26%20alert%28%22Hello%2c%20World%21%22%29%3b`,
-				`Hello%2c%20World%20%26%20O%27Reilly%5cu0021`,
-				// Quotes and parens are escaped but %69 is not over-escaped. HTML escaping is done.
-				`greeting=H%69,&amp;addressee=%28World%29`,
-				`greeting%3dH%2569%2c%26addressee%3d%28World%29%202x%2c%20https%3a%2f%2fgolang.org%2ffavicon.ico%20500.5w`,
-				`,foo/,`,
-			},
-		},
-		{
-			`<style>body { background: url('?img={{.}}') }</style>`,
-			[]string{
-				`%3cb%3e%20%22foo%25%22%20O%27Reilly%20%26bar%3b`,
-				`a%5bhref%20%3d~%20%22%2f%2fexample.com%22%5d%23foo`,
-				`Hello%2c%20%3cb%3eWorld%3c%2fb%3e%20%26amp%3btc%21`,
-				`%20dir%3d%22ltr%22`,
-				`c%20%26%26%20alert%28%22Hello%2c%20World%21%22%29%3b`,
-				`Hello%2c%20World%20%26%20O%27Reilly%5cu0021`,
-				// Quotes and parens are escaped but %69 is not over-escaped. HTML escaping is not done.
-				`greeting=H%69,&addressee=%28World%29`,
-				`greeting%3dH%2569%2c%26addressee%3d%28World%29%202x%2c%20https%3a%2f%2fgolang.org%2ffavicon.ico%20500.5w`,
-				`,foo/,`,
-			},
-		},
-		{
-			`<img srcset="{{.}}">`,
-			[]string{
-				`#ZgotmplZ`,
-				`#ZgotmplZ`,
-				// Commas are not esacped
-				`Hello,#ZgotmplZ`,
-				// Leading spaces are not percent escapes.
-				` dir=%22ltr%22`,
-				// Spaces after commas are not percent escaped.
-				`#ZgotmplZ, World!%22%29;`,
-				`Hello,#ZgotmplZ`,
-				`greeting=H%69%2c&amp;addressee=%28World%29`,
-				// Metadata is not escaped.
-				`greeting=H%69,&amp;addressee=(World) 2x, https://golang.org/favicon.ico 500.5w`,
-				`%2cfoo/%2c`,
-			},
-		},
-		{
-			`<img srcset={{.}}>`,
-			[]string{
-				`#ZgotmplZ`,
-				`#ZgotmplZ`,
-				`Hello,#ZgotmplZ`,
-				// Spaces are HTML escaped not %-escaped
-				`&#32;dir&#61;%22ltr%22`,
-				`#ZgotmplZ,&#32;World!%22%29;`,
-				`Hello,#ZgotmplZ`,
-				`greeting&#61;H%69%2c&amp;addressee&#61;%28World%29`,
-				`greeting&#61;H%69,&amp;addressee&#61;(World)&#32;2x,&#32;https://golang.org/favicon.ico&#32;500.5w`,
-				// Commas are escaped.
-				`%2cfoo/%2c`,
-			},
-		},
-		{
-			`<img srcset="{{.}} 2x, https://golang.org/ 500.5w">`,
-			[]string{
-				`#ZgotmplZ`,
-				`#ZgotmplZ`,
-				`Hello,#ZgotmplZ`,
-				` dir=%22ltr%22`,
-				`#ZgotmplZ, World!%22%29;`,
-				`Hello,#ZgotmplZ`,
-				`greeting=H%69%2c&amp;addressee=%28World%29`,
-				`greeting=H%69,&amp;addressee=(World) 2x, https://golang.org/favicon.ico 500.5w`,
-				`%2cfoo/%2c`,
-			},
-		},
-		{
-			`<img srcset="http://godoc.org/ {{.}}, https://golang.org/ 500.5w">`,
-			[]string{
-				`#ZgotmplZ`,
-				`#ZgotmplZ`,
-				`Hello,#ZgotmplZ`,
-				` dir=%22ltr%22`,
-				`#ZgotmplZ, World!%22%29;`,
-				`Hello,#ZgotmplZ`,
-				`greeting=H%69%2c&amp;addressee=%28World%29`,
-				`greeting=H%69,&amp;addressee=(World) 2x, https://golang.org/favicon.ico 500.5w`,
-				`%2cfoo/%2c`,
-			},
-		},
-		{
-			`<img srcset="http://godoc.org/?q={{.}} 2x, https://golang.org/ 500.5w">`,
-			[]string{
-				`#ZgotmplZ`,
-				`#ZgotmplZ`,
-				`Hello,#ZgotmplZ`,
-				` dir=%22ltr%22`,
-				`#ZgotmplZ, World!%22%29;`,
-				`Hello,#ZgotmplZ`,
-				`greeting=H%69%2c&amp;addressee=%28World%29`,
-				`greeting=H%69,&amp;addressee=(World) 2x, https://golang.org/favicon.ico 500.5w`,
-				`%2cfoo/%2c`,
-			},
-		},
-		{
-			`<img srcset="http://godoc.org/ 2x, {{.}} 500.5w">`,
-			[]string{
-				`#ZgotmplZ`,
-				`#ZgotmplZ`,
-				`Hello,#ZgotmplZ`,
-				` dir=%22ltr%22`,
-				`#ZgotmplZ, World!%22%29;`,
-				`Hello,#ZgotmplZ`,
-				`greeting=H%69%2c&amp;addressee=%28World%29`,
-				`greeting=H%69,&amp;addressee=(World) 2x, https://golang.org/favicon.ico 500.5w`,
-				`%2cfoo/%2c`,
-			},
-		},
-		{
-			`<img srcset="http://godoc.org/ 2x, https://golang.org/ {{.}}">`,
-			[]string{
-				`#ZgotmplZ`,
-				`#ZgotmplZ`,
-				`Hello,#ZgotmplZ`,
-				` dir=%22ltr%22`,
-				`#ZgotmplZ, World!%22%29;`,
-				`Hello,#ZgotmplZ`,
-				`greeting=H%69%2c&amp;addressee=%28World%29`,
-				`greeting=H%69,&amp;addressee=(World) 2x, https://golang.org/favicon.ico 500.5w`,
-				`%2cfoo/%2c`,
-			},
-		},
-	}
-
-	for _, test := range tests {
-		tmpl := Must(New("x").Parse(test.input))
-		pre := strings.Index(test.input, "{{.}}")
-		post := len(test.input) - (pre + 5)
-		var b bytes.Buffer
-		for i, x := range data {
-			b.Reset()
-			if err := tmpl.Execute(&b, x); err != nil {
-				t.Errorf("%q with %v: %s", test.input, x, err)
-				continue
-			}
-			if want, got := test.want[i], b.String()[pre:b.Len()-post]; want != got {
-				t.Errorf("%q with %v:\nwant\n\t%q,\ngot\n\t%q\n", test.input, x, want, got)
-				continue
-			}
-		}
-	}
-}
-
-// Test that we print using the String method. Was issue 3073.
-type myStringer struct {
-	v int
-}
-
-func (s *myStringer) String() string {
-	return fmt.Sprintf("string=%d", s.v)
-}
-
-type errorer struct {
-	v int
-}
-
-func (s *errorer) Error() string {
-	return fmt.Sprintf("error=%d", s.v)
-}
-
-func TestStringer(t *testing.T) {
-	s := &myStringer{3}
-	b := new(bytes.Buffer)
-	tmpl := Must(New("x").Parse("{{.}}"))
-	if err := tmpl.Execute(b, s); err != nil {
-		t.Fatal(err)
-	}
-	var expect = "string=3"
-	if b.String() != expect {
-		t.Errorf("expected %q got %q", expect, b.String())
-	}
-	e := &errorer{7}
-	b.Reset()
-	if err := tmpl.Execute(b, e); err != nil {
-		t.Fatal(err)
-	}
-	expect = "error=7"
-	if b.String() != expect {
-		t.Errorf("expected %q got %q", expect, b.String())
-	}
-}
-
-// https://golang.org/issue/5982
-func TestEscapingNilNonemptyInterfaces(t *testing.T) {
-	tmpl := Must(New("x").Parse("{{.E}}"))
-
-	got := new(bytes.Buffer)
-	testData := struct{ E error }{} // any non-empty interface here will do; error is just ready at hand
-	tmpl.Execute(got, testData)
-
-	// A non-empty interface should print like an empty interface.
-	want := new(bytes.Buffer)
-	data := struct{ E interface{} }{}
-	tmpl.Execute(want, data)
-
-	if !bytes.Equal(want.Bytes(), got.Bytes()) {
-		t.Errorf("expected %q got %q", string(want.Bytes()), string(got.Bytes()))
-	}
-}
diff --git a/go.dev/cmd/internal/html/template/context.go b/go.dev/cmd/internal/html/template/context.go
deleted file mode 100644
index 9b74fe7..0000000
--- a/go.dev/cmd/internal/html/template/context.go
+++ /dev/null
@@ -1,265 +0,0 @@
-// Copyright 2011 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 template
-
-import (
-	"fmt"
-
-	"golang.org/x/website/go.dev/cmd/internal/text/template/parse"
-)
-
-// context describes the state an HTML parser must be in when it reaches the
-// portion of HTML produced by evaluating a particular template node.
-//
-// The zero value of type context is the start context for a template that
-// produces an HTML fragment as defined at
-// https://www.w3.org/TR/html5/syntax.html#the-end
-// where the context element is null.
-type context struct {
-	state   state
-	delim   delim
-	urlPart urlPart
-	jsCtx   jsCtx
-	attr    attr
-	element element
-	n       parse.Node // for range break/continue
-	err     *Error
-}
-
-func (c context) String() string {
-	var err error
-	if c.err != nil {
-		err = c.err
-	}
-	return fmt.Sprintf("{%v %v %v %v %v %v %v}", c.state, c.delim, c.urlPart, c.jsCtx, c.attr, c.element, err)
-}
-
-// eq reports whether two contexts are equal.
-func (c context) eq(d context) bool {
-	return c.state == d.state &&
-		c.delim == d.delim &&
-		c.urlPart == d.urlPart &&
-		c.jsCtx == d.jsCtx &&
-		c.attr == d.attr &&
-		c.element == d.element &&
-		c.err == d.err
-}
-
-// mangle produces an identifier that includes a suffix that distinguishes it
-// from template names mangled with different contexts.
-func (c context) mangle(templateName string) string {
-	// The mangled name for the default context is the input templateName.
-	if c.state == stateText {
-		return templateName
-	}
-	s := templateName + "$htmltemplate_" + c.state.String()
-	if c.delim != delimNone {
-		s += "_" + c.delim.String()
-	}
-	if c.urlPart != urlPartNone {
-		s += "_" + c.urlPart.String()
-	}
-	if c.jsCtx != jsCtxRegexp {
-		s += "_" + c.jsCtx.String()
-	}
-	if c.attr != attrNone {
-		s += "_" + c.attr.String()
-	}
-	if c.element != elementNone {
-		s += "_" + c.element.String()
-	}
-	return s
-}
-
-// state describes a high-level HTML parser state.
-//
-// It bounds the top of the element stack, and by extension the HTML insertion
-// mode, but also contains state that does not correspond to anything in the
-// HTML5 parsing algorithm because a single token production in the HTML
-// grammar may contain embedded actions in a template. For instance, the quoted
-// HTML attribute produced by
-//     <div title="Hello {{.World}}">
-// is a single token in HTML's grammar but in a template spans several nodes.
-type state uint8
-
-//go:generate stringer -type state
-
-const (
-	// stateText is parsed character data. An HTML parser is in
-	// this state when its parse position is outside an HTML tag,
-	// directive, comment, and special element body.
-	stateText state = iota
-	// stateTag occurs before an HTML attribute or the end of a tag.
-	stateTag
-	// stateAttrName occurs inside an attribute name.
-	// It occurs between the ^'s in ` ^name^ = value`.
-	stateAttrName
-	// stateAfterName occurs after an attr name has ended but before any
-	// equals sign. It occurs between the ^'s in ` name^ ^= value`.
-	stateAfterName
-	// stateBeforeValue occurs after the equals sign but before the value.
-	// It occurs between the ^'s in ` name =^ ^value`.
-	stateBeforeValue
-	// stateHTMLCmt occurs inside an <!-- HTML comment -->.
-	stateHTMLCmt
-	// stateRCDATA occurs inside an RCDATA element (<textarea> or <title>)
-	// as described at https://www.w3.org/TR/html5/syntax.html#elements-0
-	stateRCDATA
-	// stateAttr occurs inside an HTML attribute whose content is text.
-	stateAttr
-	// stateURL occurs inside an HTML attribute whose content is a URL.
-	stateURL
-	// stateSrcset occurs inside an HTML srcset attribute.
-	stateSrcset
-	// stateJS occurs inside an event handler or script element.
-	stateJS
-	// stateJSDqStr occurs inside a JavaScript double quoted string.
-	stateJSDqStr
-	// stateJSSqStr occurs inside a JavaScript single quoted string.
-	stateJSSqStr
-	// stateJSRegexp occurs inside a JavaScript regexp literal.
-	stateJSRegexp
-	// stateJSBlockCmt occurs inside a JavaScript /* block comment */.
-	stateJSBlockCmt
-	// stateJSLineCmt occurs inside a JavaScript // line comment.
-	stateJSLineCmt
-	// stateCSS occurs inside a <style> element or style attribute.
-	stateCSS
-	// stateCSSDqStr occurs inside a CSS double quoted string.
-	stateCSSDqStr
-	// stateCSSSqStr occurs inside a CSS single quoted string.
-	stateCSSSqStr
-	// stateCSSDqURL occurs inside a CSS double quoted url("...").
-	stateCSSDqURL
-	// stateCSSSqURL occurs inside a CSS single quoted url('...').
-	stateCSSSqURL
-	// stateCSSURL occurs inside a CSS unquoted url(...).
-	stateCSSURL
-	// stateCSSBlockCmt occurs inside a CSS /* block comment */.
-	stateCSSBlockCmt
-	// stateCSSLineCmt occurs inside a CSS // line comment.
-	stateCSSLineCmt
-	// stateError is an infectious error state outside any valid
-	// HTML/CSS/JS construct.
-	stateError
-	// stateDead marks unreachable code after a {{break}} or {{continue}}.
-	stateDead
-)
-
-// isComment is true for any state that contains content meant for template
-// authors & maintainers, not for end-users or machines.
-func isComment(s state) bool {
-	switch s {
-	case stateHTMLCmt, stateJSBlockCmt, stateJSLineCmt, stateCSSBlockCmt, stateCSSLineCmt:
-		return true
-	}
-	return false
-}
-
-// isInTag return whether s occurs solely inside an HTML tag.
-func isInTag(s state) bool {
-	switch s {
-	case stateTag, stateAttrName, stateAfterName, stateBeforeValue, stateAttr:
-		return true
-	}
-	return false
-}
-
-// delim is the delimiter that will end the current HTML attribute.
-type delim uint8
-
-//go:generate stringer -type delim
-
-const (
-	// delimNone occurs outside any attribute.
-	delimNone delim = iota
-	// delimDoubleQuote occurs when a double quote (") closes the attribute.
-	delimDoubleQuote
-	// delimSingleQuote occurs when a single quote (') closes the attribute.
-	delimSingleQuote
-	// delimSpaceOrTagEnd occurs when a space or right angle bracket (>)
-	// closes the attribute.
-	delimSpaceOrTagEnd
-)
-
-// urlPart identifies a part in an RFC 3986 hierarchical URL to allow different
-// encoding strategies.
-type urlPart uint8
-
-//go:generate stringer -type urlPart
-
-const (
-	// urlPartNone occurs when not in a URL, or possibly at the start:
-	// ^ in "^http://auth/path?k=v#frag".
-	urlPartNone urlPart = iota
-	// urlPartPreQuery occurs in the scheme, authority, or path; between the
-	// ^s in "h^ttp://auth/path^?k=v#frag".
-	urlPartPreQuery
-	// urlPartQueryOrFrag occurs in the query portion between the ^s in
-	// "http://auth/path?^k=v#frag^".
-	urlPartQueryOrFrag
-	// urlPartUnknown occurs due to joining of contexts both before and
-	// after the query separator.
-	urlPartUnknown
-)
-
-// jsCtx determines whether a '/' starts a regular expression literal or a
-// division operator.
-type jsCtx uint8
-
-//go:generate stringer -type jsCtx
-
-const (
-	// jsCtxRegexp occurs where a '/' would start a regexp literal.
-	jsCtxRegexp jsCtx = iota
-	// jsCtxDivOp occurs where a '/' would start a division operator.
-	jsCtxDivOp
-	// jsCtxUnknown occurs where a '/' is ambiguous due to context joining.
-	jsCtxUnknown
-)
-
-// element identifies the HTML element when inside a start tag or special body.
-// Certain HTML element (for example <script> and <style>) have bodies that are
-// treated differently from stateText so the element type is necessary to
-// transition into the correct context at the end of a tag and to identify the
-// end delimiter for the body.
-type element uint8
-
-//go:generate stringer -type element
-
-const (
-	// elementNone occurs outside a special tag or special element body.
-	elementNone element = iota
-	// elementScript corresponds to the raw text <script> element
-	// with JS MIME type or no type attribute.
-	elementScript
-	// elementStyle corresponds to the raw text <style> element.
-	elementStyle
-	// elementTextarea corresponds to the RCDATA <textarea> element.
-	elementTextarea
-	// elementTitle corresponds to the RCDATA <title> element.
-	elementTitle
-)
-
-//go:generate stringer -type attr
-
-// attr identifies the current HTML attribute when inside the attribute,
-// that is, starting from stateAttrName until stateTag/stateText (exclusive).
-type attr uint8
-
-const (
-	// attrNone corresponds to a normal attribute or no attribute.
-	attrNone attr = iota
-	// attrScript corresponds to an event handler attribute.
-	attrScript
-	// attrScriptType corresponds to the type attribute in script HTML element
-	attrScriptType
-	// attrStyle corresponds to the style attribute whose value is CSS.
-	attrStyle
-	// attrURL corresponds to an attribute whose value is a URL.
-	attrURL
-	// attrSrcset corresponds to a srcset attribute.
-	attrSrcset
-)
diff --git a/go.dev/cmd/internal/html/template/css.go b/go.dev/cmd/internal/html/template/css.go
deleted file mode 100644
index eb92fc9..0000000
--- a/go.dev/cmd/internal/html/template/css.go
+++ /dev/null
@@ -1,260 +0,0 @@
-// Copyright 2011 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 template
-
-import (
-	"bytes"
-	"fmt"
-	"strings"
-	"unicode"
-	"unicode/utf8"
-)
-
-// endsWithCSSKeyword reports whether b ends with an ident that
-// case-insensitively matches the lower-case kw.
-func endsWithCSSKeyword(b []byte, kw string) bool {
-	i := len(b) - len(kw)
-	if i < 0 {
-		// Too short.
-		return false
-	}
-	if i != 0 {
-		r, _ := utf8.DecodeLastRune(b[:i])
-		if isCSSNmchar(r) {
-			// Too long.
-			return false
-		}
-	}
-	// Many CSS keywords, such as "!important" can have characters encoded,
-	// but the URI production does not allow that according to
-	// https://www.w3.org/TR/css3-syntax/#TOK-URI
-	// This does not attempt to recognize encoded keywords. For example,
-	// given "\75\72\6c" and "url" this return false.
-	return string(bytes.ToLower(b[i:])) == kw
-}
-
-// isCSSNmchar reports whether rune is allowed anywhere in a CSS identifier.
-func isCSSNmchar(r rune) bool {
-	// Based on the CSS3 nmchar production but ignores multi-rune escape
-	// sequences.
-	// https://www.w3.org/TR/css3-syntax/#SUBTOK-nmchar
-	return 'a' <= r && r <= 'z' ||
-		'A' <= r && r <= 'Z' ||
-		'0' <= r && r <= '9' ||
-		r == '-' ||
-		r == '_' ||
-		// Non-ASCII cases below.
-		0x80 <= r && r <= 0xd7ff ||
-		0xe000 <= r && r <= 0xfffd ||
-		0x10000 <= r && r <= 0x10ffff
-}
-
-// decodeCSS decodes CSS3 escapes given a sequence of stringchars.
-// If there is no change, it returns the input, otherwise it returns a slice
-// backed by a new array.
-// https://www.w3.org/TR/css3-syntax/#SUBTOK-stringchar defines stringchar.
-func decodeCSS(s []byte) []byte {
-	i := bytes.IndexByte(s, '\\')
-	if i == -1 {
-		return s
-	}
-	// The UTF-8 sequence for a codepoint is never longer than 1 + the
-	// number hex digits need to represent that codepoint, so len(s) is an
-	// upper bound on the output length.
-	b := make([]byte, 0, len(s))
-	for len(s) != 0 {
-		i := bytes.IndexByte(s, '\\')
-		if i == -1 {
-			i = len(s)
-		}
-		b, s = append(b, s[:i]...), s[i:]
-		if len(s) < 2 {
-			break
-		}
-		// https://www.w3.org/TR/css3-syntax/#SUBTOK-escape
-		// escape ::= unicode | '\' [#x20-#x7E#x80-#xD7FF#xE000-#xFFFD#x10000-#x10FFFF]
-		if isHex(s[1]) {
-			// https://www.w3.org/TR/css3-syntax/#SUBTOK-unicode
-			//   unicode ::= '\' [0-9a-fA-F]{1,6} wc?
-			j := 2
-			for j < len(s) && j < 7 && isHex(s[j]) {
-				j++
-			}
-			r := hexDecode(s[1:j])
-			if r > unicode.MaxRune {
-				r, j = r/16, j-1
-			}
-			n := utf8.EncodeRune(b[len(b):cap(b)], r)
-			// The optional space at the end allows a hex
-			// sequence to be followed by a literal hex.
-			// string(decodeCSS([]byte(`\A B`))) == "\nB"
-			b, s = b[:len(b)+n], skipCSSSpace(s[j:])
-		} else {
-			// `\\` decodes to `\` and `\"` to `"`.
-			_, n := utf8.DecodeRune(s[1:])
-			b, s = append(b, s[1:1+n]...), s[1+n:]
-		}
-	}
-	return b
-}
-
-// isHex reports whether the given character is a hex digit.
-func isHex(c byte) bool {
-	return '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F'
-}
-
-// hexDecode decodes a short hex digit sequence: "10" -> 16.
-func hexDecode(s []byte) rune {
-	n := '\x00'
-	for _, c := range s {
-		n <<= 4
-		switch {
-		case '0' <= c && c <= '9':
-			n |= rune(c - '0')
-		case 'a' <= c && c <= 'f':
-			n |= rune(c-'a') + 10
-		case 'A' <= c && c <= 'F':
-			n |= rune(c-'A') + 10
-		default:
-			panic(fmt.Sprintf("Bad hex digit in %q", s))
-		}
-	}
-	return n
-}
-
-// skipCSSSpace returns a suffix of c, skipping over a single space.
-func skipCSSSpace(c []byte) []byte {
-	if len(c) == 0 {
-		return c
-	}
-	// wc ::= #x9 | #xA | #xC | #xD | #x20
-	switch c[0] {
-	case '\t', '\n', '\f', ' ':
-		return c[1:]
-	case '\r':
-		// This differs from CSS3's wc production because it contains a
-		// probable spec error whereby wc contains all the single byte
-		// sequences in nl (newline) but not CRLF.
-		if len(c) >= 2 && c[1] == '\n' {
-			return c[2:]
-		}
-		return c[1:]
-	}
-	return c
-}
-
-// isCSSSpace reports whether b is a CSS space char as defined in wc.
-func isCSSSpace(b byte) bool {
-	switch b {
-	case '\t', '\n', '\f', '\r', ' ':
-		return true
-	}
-	return false
-}
-
-// cssEscaper escapes HTML and CSS special characters using \<hex>+ escapes.
-func cssEscaper(args ...interface{}) string {
-	s, _ := stringify(args...)
-	var b strings.Builder
-	r, w, written := rune(0), 0, 0
-	for i := 0; i < len(s); i += w {
-		// See comment in htmlEscaper.
-		r, w = utf8.DecodeRuneInString(s[i:])
-		var repl string
-		switch {
-		case int(r) < len(cssReplacementTable) && cssReplacementTable[r] != "":
-			repl = cssReplacementTable[r]
-		default:
-			continue
-		}
-		if written == 0 {
-			b.Grow(len(s))
-		}
-		b.WriteString(s[written:i])
-		b.WriteString(repl)
-		written = i + w
-		if repl != `\\` && (written == len(s) || isHex(s[written]) || isCSSSpace(s[written])) {
-			b.WriteByte(' ')
-		}
-	}
-	if written == 0 {
-		return s
-	}
-	b.WriteString(s[written:])
-	return b.String()
-}
-
-var cssReplacementTable = []string{
-	0:    `\0`,
-	'\t': `\9`,
-	'\n': `\a`,
-	'\f': `\c`,
-	'\r': `\d`,
-	// Encode HTML specials as hex so the output can be embedded
-	// in HTML attributes without further encoding.
-	'"':  `\22`,
-	'&':  `\26`,
-	'\'': `\27`,
-	'(':  `\28`,
-	')':  `\29`,
-	'+':  `\2b`,
-	'/':  `\2f`,
-	':':  `\3a`,
-	';':  `\3b`,
-	'<':  `\3c`,
-	'>':  `\3e`,
-	'\\': `\\`,
-	'{':  `\7b`,
-	'}':  `\7d`,
-}
-
-var expressionBytes = []byte("expression")
-var mozBindingBytes = []byte("mozbinding")
-
-// cssValueFilter allows innocuous CSS values in the output including CSS
-// quantities (10px or 25%), ID or class literals (#foo, .bar), keyword values
-// (inherit, blue), and colors (#888).
-// It filters out unsafe values, such as those that affect token boundaries,
-// and anything that might execute scripts.
-func cssValueFilter(args ...interface{}) string {
-	s, t := stringify(args...)
-	if t == contentTypeCSS {
-		return s
-	}
-	b, id := decodeCSS([]byte(s)), make([]byte, 0, 64)
-
-	// CSS3 error handling is specified as honoring string boundaries per
-	// https://www.w3.org/TR/css3-syntax/#error-handling :
-	//     Malformed declarations. User agents must handle unexpected
-	//     tokens encountered while parsing a declaration by reading until
-	//     the end of the declaration, while observing the rules for
-	//     matching pairs of (), [], {}, "", and '', and correctly handling
-	//     escapes. For example, a malformed declaration may be missing a
-	//     property, colon (:) or value.
-	// So we need to make sure that values do not have mismatched bracket
-	// or quote characters to prevent the browser from restarting parsing
-	// inside a string that might embed JavaScript source.
-	for i, c := range b {
-		switch c {
-		case 0, '"', '\'', '(', ')', '/', ';', '@', '[', '\\', ']', '`', '{', '}':
-			return filterFailsafe
-		case '-':
-			// Disallow <!-- or -->.
-			// -- should not appear in valid identifiers.
-			if i != 0 && b[i-1] == '-' {
-				return filterFailsafe
-			}
-		default:
-			if c < utf8.RuneSelf && isCSSNmchar(rune(c)) {
-				id = append(id, c)
-			}
-		}
-	}
-	id = bytes.ToLower(id)
-	if bytes.Contains(id, expressionBytes) || bytes.Contains(id, mozBindingBytes) {
-		return filterFailsafe
-	}
-	return string(b)
-}
diff --git a/go.dev/cmd/internal/html/template/css_test.go b/go.dev/cmd/internal/html/template/css_test.go
deleted file mode 100644
index a735638..0000000
--- a/go.dev/cmd/internal/html/template/css_test.go
+++ /dev/null
@@ -1,281 +0,0 @@
-// Copyright 2011 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 template
-
-import (
-	"strconv"
-	"strings"
-	"testing"
-)
-
-func TestEndsWithCSSKeyword(t *testing.T) {
-	tests := []struct {
-		css, kw string
-		want    bool
-	}{
-		{"", "url", false},
-		{"url", "url", true},
-		{"URL", "url", true},
-		{"Url", "url", true},
-		{"url", "important", false},
-		{"important", "important", true},
-		{"image-url", "url", false},
-		{"imageurl", "url", false},
-		{"image url", "url", true},
-	}
-	for _, test := range tests {
-		got := endsWithCSSKeyword([]byte(test.css), test.kw)
-		if got != test.want {
-			t.Errorf("want %t but got %t for css=%v, kw=%v", test.want, got, test.css, test.kw)
-		}
-	}
-}
-
-func TestIsCSSNmchar(t *testing.T) {
-	tests := []struct {
-		rune rune
-		want bool
-	}{
-		{0, false},
-		{'0', true},
-		{'9', true},
-		{'A', true},
-		{'Z', true},
-		{'a', true},
-		{'z', true},
-		{'_', true},
-		{'-', true},
-		{':', false},
-		{';', false},
-		{' ', false},
-		{0x7f, false},
-		{0x80, true},
-		{0x1234, true},
-		{0xd800, false},
-		{0xdc00, false},
-		{0xfffe, false},
-		{0x10000, true},
-		{0x110000, false},
-	}
-	for _, test := range tests {
-		got := isCSSNmchar(test.rune)
-		if got != test.want {
-			t.Errorf("%q: want %t but got %t", string(test.rune), test.want, got)
-		}
-	}
-}
-
-func TestDecodeCSS(t *testing.T) {
-	tests := []struct {
-		css, want string
-	}{
-		{``, ``},
-		{`foo`, `foo`},
-		{`foo\`, `foo`},
-		{`foo\\`, `foo\`},
-		{`\`, ``},
-		{`\A`, "\n"},
-		{`\a`, "\n"},
-		{`\0a`, "\n"},
-		{`\00000a`, "\n"},
-		{`\000000a`, "\u0000a"},
-		{`\1234 5`, "\u1234" + "5"},
-		{`\1234\20 5`, "\u1234" + " 5"},
-		{`\1234\A 5`, "\u1234" + "\n5"},
-		{"\\1234\t5", "\u1234" + "5"},
-		{"\\1234\n5", "\u1234" + "5"},
-		{"\\1234\r\n5", "\u1234" + "5"},
-		{`\12345`, "\U00012345"},
-		{`\\`, `\`},
-		{`\\ `, `\ `},
-		{`\"`, `"`},
-		{`\'`, `'`},
-		{`\.`, `.`},
-		{`\. .`, `. .`},
-		{
-			`The \3c i\3equick\3c/i\3e,\d\A\3cspan style=\27 color:brown\27\3e brown\3c/span\3e  fox jumps\2028over the \3c canine class=\22lazy\22 \3e dog\3c/canine\3e`,
-			"The <i>quick</i>,\r\n<span style='color:brown'>brown</span> fox jumps\u2028over the <canine class=\"lazy\">dog</canine>",
-		},
-	}
-	for _, test := range tests {
-		got1 := string(decodeCSS([]byte(test.css)))
-		if got1 != test.want {
-			t.Errorf("%q: want\n\t%q\nbut got\n\t%q", test.css, test.want, got1)
-		}
-		recoded := cssEscaper(got1)
-		if got2 := string(decodeCSS([]byte(recoded))); got2 != test.want {
-			t.Errorf("%q: escape & decode not dual for %q", test.css, recoded)
-		}
-	}
-}
-
-func TestHexDecode(t *testing.T) {
-	for i := 0; i < 0x200000; i += 101 /* coprime with 16 */ {
-		s := strconv.FormatInt(int64(i), 16)
-		if got := int(hexDecode([]byte(s))); got != i {
-			t.Errorf("%s: want %d but got %d", s, i, got)
-		}
-		s = strings.ToUpper(s)
-		if got := int(hexDecode([]byte(s))); got != i {
-			t.Errorf("%s: want %d but got %d", s, i, got)
-		}
-	}
-}
-
-func TestSkipCSSSpace(t *testing.T) {
-	tests := []struct {
-		css, want string
-	}{
-		{"", ""},
-		{"foo", "foo"},
-		{"\n", ""},
-		{"\r\n", ""},
-		{"\r", ""},
-		{"\t", ""},
-		{" ", ""},
-		{"\f", ""},
-		{" foo", "foo"},
-		{"  foo", " foo"},
-		{`\20`, `\20`},
-	}
-	for _, test := range tests {
-		got := string(skipCSSSpace([]byte(test.css)))
-		if got != test.want {
-			t.Errorf("%q: want %q but got %q", test.css, test.want, got)
-		}
-	}
-}
-
-func TestCSSEscaper(t *testing.T) {
-	input := ("\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f" +
-		"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" +
-		` !"#$%&'()*+,-./` +
-		`0123456789:;<=>?` +
-		`@ABCDEFGHIJKLMNO` +
-		`PQRSTUVWXYZ[\]^_` +
-		"`abcdefghijklmno" +
-		"pqrstuvwxyz{|}~\x7f" +
-		"\u00A0\u0100\u2028\u2029\ufeff\U0001D11E")
-
-	want := ("\\0\x01\x02\x03\x04\x05\x06\x07" +
-		"\x08\\9 \\a\x0b\\c \\d\x0E\x0F" +
-		"\x10\x11\x12\x13\x14\x15\x16\x17" +
-		"\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" +
-		` !\22#$%\26\27\28\29*\2b,-.\2f ` +
-		`0123456789\3a\3b\3c=\3e?` +
-		`@ABCDEFGHIJKLMNO` +
-		`PQRSTUVWXYZ[\\]^_` +
-		"`abcdefghijklmno" +
-		`pqrstuvwxyz\7b|\7d~` + "\u007f" +
-		"\u00A0\u0100\u2028\u2029\ufeff\U0001D11E")
-
-	got := cssEscaper(input)
-	if got != want {
-		t.Errorf("encode: want\n\t%q\nbut got\n\t%q", want, got)
-	}
-
-	got = string(decodeCSS([]byte(got)))
-	if input != got {
-		t.Errorf("decode: want\n\t%q\nbut got\n\t%q", input, got)
-	}
-}
-
-func TestCSSValueFilter(t *testing.T) {
-	tests := []struct {
-		css, want string
-	}{
-		{"", ""},
-		{"foo", "foo"},
-		{"0", "0"},
-		{"0px", "0px"},
-		{"-5px", "-5px"},
-		{"1.25in", "1.25in"},
-		{"+.33em", "+.33em"},
-		{"100%", "100%"},
-		{"12.5%", "12.5%"},
-		{".foo", ".foo"},
-		{"#bar", "#bar"},
-		{"corner-radius", "corner-radius"},
-		{"-moz-corner-radius", "-moz-corner-radius"},
-		{"#000", "#000"},
-		{"#48f", "#48f"},
-		{"#123456", "#123456"},
-		{"U+00-FF, U+980-9FF", "U+00-FF, U+980-9FF"},
-		{"color: red", "color: red"},
-		{"<!--", "ZgotmplZ"},
-		{"-->", "ZgotmplZ"},
-		{"<![CDATA[", "ZgotmplZ"},
-		{"]]>", "ZgotmplZ"},
-		{"</style", "ZgotmplZ"},
-		{`"`, "ZgotmplZ"},
-		{`'`, "ZgotmplZ"},
-		{"`", "ZgotmplZ"},
-		{"\x00", "ZgotmplZ"},
-		{"/* foo */", "ZgotmplZ"},
-		{"//", "ZgotmplZ"},
-		{"[href=~", "ZgotmplZ"},
-		{"expression(alert(1337))", "ZgotmplZ"},
-		{"-expression(alert(1337))", "ZgotmplZ"},
-		{"expression", "ZgotmplZ"},
-		{"Expression", "ZgotmplZ"},
-		{"EXPRESSION", "ZgotmplZ"},
-		{"-moz-binding", "ZgotmplZ"},
-		{"-expr\x00ession(alert(1337))", "ZgotmplZ"},
-		{`-expr\0ession(alert(1337))`, "ZgotmplZ"},
-		{`-express\69on(alert(1337))`, "ZgotmplZ"},
-		{`-express\69 on(alert(1337))`, "ZgotmplZ"},
-		{`-exp\72 ession(alert(1337))`, "ZgotmplZ"},
-		{`-exp\52 ession(alert(1337))`, "ZgotmplZ"},
-		{`-exp\000052 ession(alert(1337))`, "ZgotmplZ"},
-		{`-expre\0000073sion`, "-expre\x073sion"},
-		{`@import url evil.css`, "ZgotmplZ"},
-	}
-	for _, test := range tests {
-		got := cssValueFilter(test.css)
-		if got != test.want {
-			t.Errorf("%q: want %q but got %q", test.css, test.want, got)
-		}
-	}
-}
-
-func BenchmarkCSSEscaper(b *testing.B) {
-	for i := 0; i < b.N; i++ {
-		cssEscaper("The <i>quick</i>,\r\n<span style='color:brown'>brown</span> fox jumps\u2028over the <canine class=\"lazy\">dog</canine>")
-	}
-}
-
-func BenchmarkCSSEscaperNoSpecials(b *testing.B) {
-	for i := 0; i < b.N; i++ {
-		cssEscaper("The quick, brown fox jumps over the lazy dog.")
-	}
-}
-
-func BenchmarkDecodeCSS(b *testing.B) {
-	s := []byte(`The \3c i\3equick\3c/i\3e,\d\A\3cspan style=\27 color:brown\27\3e brown\3c/span\3e fox jumps\2028over the \3c canine class=\22lazy\22 \3edog\3c/canine\3e`)
-	b.ResetTimer()
-	for i := 0; i < b.N; i++ {
-		decodeCSS(s)
-	}
-}
-
-func BenchmarkDecodeCSSNoSpecials(b *testing.B) {
-	s := []byte("The quick, brown fox jumps over the lazy dog.")
-	b.ResetTimer()
-	for i := 0; i < b.N; i++ {
-		decodeCSS(s)
-	}
-}
-
-func BenchmarkCSSValueFilter(b *testing.B) {
-	for i := 0; i < b.N; i++ {
-		cssValueFilter(`  e\78preS\0Sio/**/n(alert(1337))`)
-	}
-}
-
-func BenchmarkCSSValueFilterOk(b *testing.B) {
-	for i := 0; i < b.N; i++ {
-		cssValueFilter(`Times New Roman`)
-	}
-}
diff --git a/go.dev/cmd/internal/html/template/delim_string.go b/go.dev/cmd/internal/html/template/delim_string.go
deleted file mode 100644
index 6d80e09..0000000
--- a/go.dev/cmd/internal/html/template/delim_string.go
+++ /dev/null
@@ -1,16 +0,0 @@
-// Code generated by "stringer -type delim"; DO NOT EDIT.
-
-package template
-
-import "strconv"
-
-const _delim_name = "delimNonedelimDoubleQuotedelimSingleQuotedelimSpaceOrTagEnd"
-
-var _delim_index = [...]uint8{0, 9, 25, 41, 59}
-
-func (i delim) String() string {
-	if i >= delim(len(_delim_index)-1) {
-		return "delim(" + strconv.FormatInt(int64(i), 10) + ")"
-	}
-	return _delim_name[_delim_index[i]:_delim_index[i+1]]
-}
diff --git a/go.dev/cmd/internal/html/template/doc.go b/go.dev/cmd/internal/html/template/doc.go
deleted file mode 100644
index fb3f173..0000000
--- a/go.dev/cmd/internal/html/template/doc.go
+++ /dev/null
@@ -1,241 +0,0 @@
-// Copyright 2011 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 template (html/template) implements data-driven templates for
-generating HTML output safe against code injection. It provides the
-same interface as package text/template and should be used instead of
-text/template whenever the output is HTML.
-
-The documentation here focuses on the security features of the package.
-For information about how to program the templates themselves, see the
-documentation for text/template.
-
-Introduction
-
-This package wraps package text/template so you can share its template API
-to parse and execute HTML templates safely.
-
-  tmpl, err := template.New("name").Parse(...)
-  // Error checking elided
-  err = tmpl.Execute(out, data)
-
-If successful, tmpl will now be injection-safe. Otherwise, err is an error
-defined in the docs for ErrorCode.
-
-HTML templates treat data values as plain text which should be encoded so they
-can be safely embedded in an HTML document. The escaping is contextual, so
-actions can appear within JavaScript, CSS, and URI contexts.
-
-The security model used by this package assumes that template authors are
-trusted, while Execute's data parameter is not. More details are
-provided below.
-
-Example
-
-  import "golang.org/x/website/go.dev/cmd/internal/text/template"
-  ...
-  t, err := template.New("foo").Parse(`{{define "T"}}Hello, {{.}}!{{end}}`)
-  err = t.ExecuteTemplate(out, "T", "<script>alert('you have been pwned')</script>")
-
-produces
-
-  Hello, <script>alert('you have been pwned')</script>!
-
-but the contextual autoescaping in html/template
-
-  import "golang.org/x/website/go.dev/cmd/internal/html/template"
-  ...
-  t, err := template.New("foo").Parse(`{{define "T"}}Hello, {{.}}!{{end}}`)
-  err = t.ExecuteTemplate(out, "T", "<script>alert('you have been pwned')</script>")
-
-produces safe, escaped HTML output
-
-  Hello, &lt;script&gt;alert(&#39;you have been pwned&#39;)&lt;/script&gt;!
-
-
-Contexts
-
-This package understands HTML, CSS, JavaScript, and URIs. It adds sanitizing
-functions to each simple action pipeline, so given the excerpt
-
-  <a href="/search?q={{.}}">{{.}}</a>
-
-At parse time each {{.}} is overwritten to add escaping functions as necessary.
-In this case it becomes
-
-  <a href="/search?q={{. | urlescaper | attrescaper}}">{{. | htmlescaper}}</a>
-
-where urlescaper, attrescaper, and htmlescaper are aliases for internal escaping
-functions.
-
-For these internal escaping functions, if an action pipeline evaluates to
-a nil interface value, it is treated as though it were an empty string.
-
-Namespaced and data- attributes
-
-Attributes with a namespace are treated as if they had no namespace.
-Given the excerpt
-
-  <a my:href="{{.}}"></a>
-
-At parse time the attribute will be treated as if it were just "href".
-So at parse time the template becomes:
-
-  <a my:href="{{. | urlescaper | attrescaper}}"></a>
-
-Similarly to attributes with namespaces, attributes with a "data-" prefix are
-treated as if they had no "data-" prefix. So given
-
-  <a data-href="{{.}}"></a>
-
-At parse time this becomes
-
-  <a data-href="{{. | urlescaper | attrescaper}}"></a>
-
-If an attribute has both a namespace and a "data-" prefix, only the namespace
-will be removed when determining the context. For example
-
-  <a my:data-href="{{.}}"></a>
-
-This is handled as if "my:data-href" was just "data-href" and not "href" as
-it would be if the "data-" prefix were to be ignored too. Thus at parse
-time this becomes just
-
-  <a my:data-href="{{. | attrescaper}}"></a>
-
-As a special case, attributes with the namespace "xmlns" are always treated
-as containing URLs. Given the excerpts
-
-  <a xmlns:title="{{.}}"></a>
-  <a xmlns:href="{{.}}"></a>
-  <a xmlns:onclick="{{.}}"></a>
-
-At parse time they become:
-
-  <a xmlns:title="{{. | urlescaper | attrescaper}}"></a>
-  <a xmlns:href="{{. | urlescaper | attrescaper}}"></a>
-  <a xmlns:onclick="{{. | urlescaper | attrescaper}}"></a>
-
-Errors
-
-See the documentation of ErrorCode for details.
-
-
-A fuller picture
-
-The rest of this package comment may be skipped on first reading; it includes
-details necessary to understand escaping contexts and error messages. Most users
-will not need to understand these details.
-
-
-Contexts
-
-Assuming {{.}} is `O'Reilly: How are <i>you</i>?`, the table below shows
-how {{.}} appears when used in the context to the left.
-
-  Context                          {{.}} After
-  {{.}}                            O'Reilly: How are &lt;i&gt;you&lt;/i&gt;?
-  <a title='{{.}}'>                O&#39;Reilly: How are you?
-  <a href="/{{.}}">                O&#39;Reilly: How are %3ci%3eyou%3c/i%3e?
-  <a href="?q={{.}}">              O&#39;Reilly%3a%20How%20are%3ci%3e...%3f
-  <a onx='f("{{.}}")'>             O\x27Reilly: How are \x3ci\x3eyou...?
-  <a onx='f({{.}})'>               "O\x27Reilly: How are \x3ci\x3eyou...?"
-  <a onx='pattern = /{{.}}/;'>     O\x27Reilly: How are \x3ci\x3eyou...\x3f
-
-If used in an unsafe context, then the value might be filtered out:
-
-  Context                          {{.}} After
-  <a href="{{.}}">                 #ZgotmplZ
-
-since "O'Reilly:" is not an allowed protocol like "http:".
-
-
-If {{.}} is the innocuous word, `left`, then it can appear more widely,
-
-  Context                              {{.}} After
-  {{.}}                                left
-  <a title='{{.}}'>                    left
-  <a href='{{.}}'>                     left
-  <a href='/{{.}}'>                    left
-  <a href='?dir={{.}}'>                left
-  <a style="border-{{.}}: 4px">        left
-  <a style="align: {{.}}">             left
-  <a style="background: '{{.}}'>       left
-  <a style="background: url('{{.}}')>  left
-  <style>p.{{.}} {color:red}</style>   left
-
-Non-string values can be used in JavaScript contexts.
-If {{.}} is
-
-  struct{A,B string}{ "foo", "bar" }
-
-in the escaped template
-
-  <script>var pair = {{.}};</script>
-
-then the template output is
-
-  <script>var pair = {"A": "foo", "B": "bar"};</script>
-
-See package json to understand how non-string content is marshaled for
-embedding in JavaScript contexts.
-
-
-Typed Strings
-
-By default, this package assumes that all pipelines produce a plain text string.
-It adds escaping pipeline stages necessary to correctly and safely embed that
-plain text string in the appropriate context.
-
-When a data value is not plain text, you can make sure it is not over-escaped
-by marking it with its type.
-
-Types HTML, JS, URL, and others from content.go can carry safe content that is
-exempted from escaping.
-
-The template
-
-  Hello, {{.}}!
-
-can be invoked with
-
-  tmpl.Execute(out, template.HTML(`<b>World</b>`))
-
-to produce
-
-  Hello, <b>World</b>!
-
-instead of the
-
-  Hello, &lt;b&gt;World&lt;b&gt;!
-
-that would have been produced if {{.}} was a regular string.
-
-
-Security Model
-
-https://rawgit.com/mikesamuel/sanitized-jquery-templates/trunk/safetemplate.html#problem_definition defines "safe" as used by this package.
-
-This package assumes that template authors are trusted, that Execute's data
-parameter is not, and seeks to preserve the properties below in the face
-of untrusted data:
-
-Structure Preservation Property:
-"... when a template author writes an HTML tag in a safe templating language,
-the browser will interpret the corresponding portion of the output as a tag
-regardless of the values of untrusted data, and similarly for other structures
-such as attribute boundaries and JS and CSS string boundaries."
-
-Code Effect Property:
-"... only code specified by the template author should run as a result of
-injecting the template output into a page and all code specified by the
-template author should run as a result of the same."
-
-Least Surprise Property:
-"A developer (or code reviewer) familiar with HTML, CSS, and JavaScript, who
-knows that contextual autoescaping happens should be able to look at a {{.}}
-and correctly infer what sanitization happens."
-*/
-package template
diff --git a/go.dev/cmd/internal/html/template/element_string.go b/go.dev/cmd/internal/html/template/element_string.go
deleted file mode 100644
index 4573e08..0000000
--- a/go.dev/cmd/internal/html/template/element_string.go
+++ /dev/null
@@ -1,16 +0,0 @@
-// Code generated by "stringer -type element"; DO NOT EDIT.
-
-package template
-
-import "strconv"
-
-const _element_name = "elementNoneelementScriptelementStyleelementTextareaelementTitle"
-
-var _element_index = [...]uint8{0, 11, 24, 36, 51, 63}
-
-func (i element) String() string {
-	if i >= element(len(_element_index)-1) {
-		return "element(" + strconv.FormatInt(int64(i), 10) + ")"
-	}
-	return _element_name[_element_index[i]:_element_index[i+1]]
-}
diff --git a/go.dev/cmd/internal/html/template/error.go b/go.dev/cmd/internal/html/template/error.go
deleted file mode 100644
index c8a041f..0000000
--- a/go.dev/cmd/internal/html/template/error.go
+++ /dev/null
@@ -1,234 +0,0 @@
-// Copyright 2011 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 template
-
-import (
-	"fmt"
-
-	"golang.org/x/website/go.dev/cmd/internal/text/template/parse"
-)
-
-// Error describes a problem encountered during template Escaping.
-type Error struct {
-	// ErrorCode describes the kind of error.
-	ErrorCode ErrorCode
-	// Node is the node that caused the problem, if known.
-	// If not nil, it overrides Name and Line.
-	Node parse.Node
-	// Name is the name of the template in which the error was encountered.
-	Name string
-	// Line is the line number of the error in the template source or 0.
-	Line int
-	// Description is a human-readable description of the problem.
-	Description string
-}
-
-// ErrorCode is a code for a kind of error.
-type ErrorCode int
-
-// We define codes for each error that manifests while escaping templates, but
-// escaped templates may also fail at runtime.
-//
-// Output: "ZgotmplZ"
-// Example:
-//   <img src="{{.X}}">
-//   where {{.X}} evaluates to `javascript:...`
-// Discussion:
-//   "ZgotmplZ" is a special value that indicates that unsafe content reached a
-//   CSS or URL context at runtime. The output of the example will be
-//     <img src="#ZgotmplZ">
-//   If the data comes from a trusted source, use content types to exempt it
-//   from filtering: URL(`javascript:...`).
-const (
-	// OK indicates the lack of an error.
-	OK ErrorCode = iota
-
-	// ErrAmbigContext: "... appears in an ambiguous context within a URL"
-	// Example:
-	//   <a href="
-	//      {{if .C}}
-	//        /path/
-	//      {{else}}
-	//        /search?q=
-	//      {{end}}
-	//      {{.X}}
-	//   ">
-	// Discussion:
-	//   {{.X}} is in an ambiguous URL context since, depending on {{.C}},
-	//  it may be either a URL suffix or a query parameter.
-	//   Moving {{.X}} into the condition removes the ambiguity:
-	//   <a href="{{if .C}}/path/{{.X}}{{else}}/search?q={{.X}}">
-	ErrAmbigContext
-
-	// ErrBadHTML: "expected space, attr name, or end of tag, but got ...",
-	//   "... in unquoted attr", "... in attribute name"
-	// Example:
-	//   <a href = /search?q=foo>
-	//   <href=foo>
-	//   <form na<e=...>
-	//   <option selected<
-	// Discussion:
-	//   This is often due to a typo in an HTML element, but some runes
-	//   are banned in tag names, attribute names, and unquoted attribute
-	//   values because they can tickle parser ambiguities.
-	//   Quoting all attributes is the best policy.
-	ErrBadHTML
-
-	// ErrBranchEnd: "{{if}} branches end in different contexts"
-	// Example:
-	//   {{if .C}}<a href="{{end}}{{.X}}
-	// Discussion:
-	//   Package html/template statically examines each path through an
-	//   {{if}}, {{range}}, or {{with}} to escape any following pipelines.
-	//   The example is ambiguous since {{.X}} might be an HTML text node,
-	//   or a URL prefix in an HTML attribute. The context of {{.X}} is
-	//   used to figure out how to escape it, but that context depends on
-	//   the run-time value of {{.C}} which is not statically known.
-	//
-	//   The problem is usually something like missing quotes or angle
-	//   brackets, or can be avoided by refactoring to put the two contexts
-	//   into different branches of an if, range or with. If the problem
-	//   is in a {{range}} over a collection that should never be empty,
-	//   adding a dummy {{else}} can help.
-	ErrBranchEnd
-
-	// ErrEndContext: "... ends in a non-text context: ..."
-	// Examples:
-	//   <div
-	//   <div title="no close quote>
-	//   <script>f()
-	// Discussion:
-	//   Executed templates should produce a DocumentFragment of HTML.
-	//   Templates that end without closing tags will trigger this error.
-	//   Templates that should not be used in an HTML context or that
-	//   produce incomplete Fragments should not be executed directly.
-	//
-	//   {{define "main"}} <script>{{template "helper"}}</script> {{end}}
-	//   {{define "helper"}} document.write(' <div title=" ') {{end}}
-	//
-	//   "helper" does not produce a valid document fragment, so should
-	//   not be Executed directly.
-	ErrEndContext
-
-	// ErrNoSuchTemplate: "no such template ..."
-	// Examples:
-	//   {{define "main"}}<div {{template "attrs"}}>{{end}}
-	//   {{define "attrs"}}href="{{.URL}}"{{end}}
-	// Discussion:
-	//   Package html/template looks through template calls to compute the
-	//   context.
-	//   Here the {{.URL}} in "attrs" must be treated as a URL when called
-	//   from "main", but you will get this error if "attrs" is not defined
-	//   when "main" is parsed.
-	ErrNoSuchTemplate
-
-	// ErrOutputContext: "cannot compute output context for template ..."
-	// Examples:
-	//   {{define "t"}}{{if .T}}{{template "t" .T}}{{end}}{{.H}}",{{end}}
-	// Discussion:
-	//   A recursive template does not end in the same context in which it
-	//   starts, and a reliable output context cannot be computed.
-	//   Look for typos in the named template.
-	//   If the template should not be called in the named start context,
-	//   look for calls to that template in unexpected contexts.
-	//   Maybe refactor recursive templates to not be recursive.
-	ErrOutputContext
-
-	// ErrPartialCharset: "unfinished JS regexp charset in ..."
-	// Example:
-	//     <script>var pattern = /foo[{{.Chars}}]/</script>
-	// Discussion:
-	//   Package html/template does not support interpolation into regular
-	//   expression literal character sets.
-	ErrPartialCharset
-
-	// ErrPartialEscape: "unfinished escape sequence in ..."
-	// Example:
-	//   <script>alert("\{{.X}}")</script>
-	// Discussion:
-	//   Package html/template does not support actions following a
-	//   backslash.
-	//   This is usually an error and there are better solutions; for
-	//   example
-	//     <script>alert("{{.X}}")</script>
-	//   should work, and if {{.X}} is a partial escape sequence such as
-	//   "xA0", mark the whole sequence as safe content: JSStr(`\xA0`)
-	ErrPartialEscape
-
-	// ErrRangeLoopReentry: "on range loop re-entry: ..."
-	// Example:
-	//   <script>var x = [{{range .}}'{{.}},{{end}}]</script>
-	// Discussion:
-	//   If an iteration through a range would cause it to end in a
-	//   different context than an earlier pass, there is no single context.
-	//   In the example, there is missing a quote, so it is not clear
-	//   whether {{.}} is meant to be inside a JS string or in a JS value
-	//   context. The second iteration would produce something like
-	//
-	//     <script>var x = ['firstValue,'secondValue]</script>
-	ErrRangeLoopReentry
-
-	// ErrSlashAmbig: '/' could start a division or regexp.
-	// Example:
-	//   <script>
-	//     {{if .C}}var x = 1{{end}}
-	//     /-{{.N}}/i.test(x) ? doThis : doThat();
-	//   </script>
-	// Discussion:
-	//   The example above could produce `var x = 1/-2/i.test(s)...`
-	//   in which the first '/' is a mathematical division operator or it
-	//   could produce `/-2/i.test(s)` in which the first '/' starts a
-	//   regexp literal.
-	//   Look for missing semicolons inside branches, and maybe add
-	//   parentheses to make it clear which interpretation you intend.
-	ErrSlashAmbig
-
-	// ErrPredefinedEscaper: "predefined escaper ... disallowed in template"
-	// Example:
-	//   <div class={{. | html}}>Hello<div>
-	// Discussion:
-	//   Package html/template already contextually escapes all pipelines to
-	//   produce HTML output safe against code injection. Manually escaping
-	//   pipeline output using the predefined escapers "html" or "urlquery" is
-	//   unnecessary, and may affect the correctness or safety of the escaped
-	//   pipeline output in Go 1.8 and earlier.
-	//
-	//   In most cases, such as the given example, this error can be resolved by
-	//   simply removing the predefined escaper from the pipeline and letting the
-	//   contextual autoescaper handle the escaping of the pipeline. In other
-	//   instances, where the predefined escaper occurs in the middle of a
-	//   pipeline where subsequent commands expect escaped input, e.g.
-	//     {{.X | html | makeALink}}
-	//   where makeALink does
-	//     return `<a href="`+input+`">link</a>`
-	//   consider refactoring the surrounding template to make use of the
-	//   contextual autoescaper, i.e.
-	//     <a href="{{.X}}">link</a>
-	//
-	//   To ease migration to Go 1.9 and beyond, "html" and "urlquery" will
-	//   continue to be allowed as the last command in a pipeline. However, if the
-	//   pipeline occurs in an unquoted attribute value context, "html" is
-	//   disallowed. Avoid using "html" and "urlquery" entirely in new templates.
-	ErrPredefinedEscaper
-)
-
-func (e *Error) Error() string {
-	switch {
-	case e.Node != nil:
-		loc, _ := (*parse.Tree)(nil).ErrorContext(e.Node)
-		return fmt.Sprintf("golang.org/x/website/go.dev/cmd/internal/html/template:%s: %s", loc, e.Description)
-	case e.Line != 0:
-		return fmt.Sprintf("golang.org/x/website/go.dev/cmd/internal/html/template:%s:%d: %s", e.Name, e.Line, e.Description)
-	case e.Name != "":
-		return fmt.Sprintf("golang.org/x/website/go.dev/cmd/internal/html/template:%s: %s", e.Name, e.Description)
-	}
-	return "golang.org/x/website/go.dev/cmd/internal/html/template: " + e.Description
-}
-
-// errorf creates an error given a format string f and args.
-// The template Name still needs to be supplied.
-func errorf(k ErrorCode, node parse.Node, line int, f string, args ...interface{}) *Error {
-	return &Error{k, node, "", line, fmt.Sprintf(f, args...)}
-}
diff --git a/go.dev/cmd/internal/html/template/escape.go b/go.dev/cmd/internal/html/template/escape.go
deleted file mode 100644
index 959c871..0000000
--- a/go.dev/cmd/internal/html/template/escape.go
+++ /dev/null
@@ -1,962 +0,0 @@
-// Copyright 2011 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 template
-
-import (
-	"bytes"
-	"fmt"
-	"html"
-	"io"
-
-	"golang.org/x/website/go.dev/cmd/internal/text/template"
-	"golang.org/x/website/go.dev/cmd/internal/text/template/parse"
-)
-
-// escapeTemplate rewrites the named template, which must be
-// associated with t, to guarantee that the output of any of the named
-// templates is properly escaped. If no error is returned, then the named templates have
-// been modified. Otherwise the named templates have been rendered
-// unusable.
-func escapeTemplate(tmpl *Template, node parse.Node, name string) error {
-	c, _ := tmpl.esc.escapeTree(context{}, node, name, 0)
-	var err error
-	if c.err != nil {
-		err, c.err.Name = c.err, name
-	} else if c.state != stateText {
-		err = &Error{ErrEndContext, nil, name, 0, fmt.Sprintf("ends in a non-text context: %v", c)}
-	}
-	if err != nil {
-		// Prevent execution of unsafe templates.
-		if t := tmpl.set[name]; t != nil {
-			t.escapeErr = err
-			t.text.Tree = nil
-			t.Tree = nil
-		}
-		return err
-	}
-	tmpl.esc.commit()
-	if t := tmpl.set[name]; t != nil {
-		t.escapeErr = escapeOK
-		t.Tree = t.text.Tree
-	}
-	return nil
-}
-
-// evalArgs formats the list of arguments into a string. It is equivalent to
-// fmt.Sprint(args...), except that it deferences all pointers.
-func evalArgs(args ...interface{}) string {
-	// Optimization for simple common case of a single string argument.
-	if len(args) == 1 {
-		if s, ok := args[0].(string); ok {
-			return s
-		}
-	}
-	for i, arg := range args {
-		args[i] = indirectToStringerOrError(arg)
-	}
-	return fmt.Sprint(args...)
-}
-
-// funcMap maps command names to functions that render their inputs safe.
-var funcMap = template.FuncMap{
-	"_html_template_attrescaper":     attrEscaper,
-	"_html_template_commentescaper":  commentEscaper,
-	"_html_template_cssescaper":      cssEscaper,
-	"_html_template_cssvaluefilter":  cssValueFilter,
-	"_html_template_htmlnamefilter":  htmlNameFilter,
-	"_html_template_htmlescaper":     htmlEscaper,
-	"_html_template_jsregexpescaper": jsRegexpEscaper,
-	"_html_template_jsstrescaper":    jsStrEscaper,
-	"_html_template_jsvalescaper":    jsValEscaper,
-	"_html_template_nospaceescaper":  htmlNospaceEscaper,
-	"_html_template_rcdataescaper":   rcdataEscaper,
-	"_html_template_srcsetescaper":   srcsetFilterAndEscaper,
-	"_html_template_urlescaper":      urlEscaper,
-	"_html_template_urlfilter":       urlFilter,
-	"_html_template_urlnormalizer":   urlNormalizer,
-	"_eval_args_":                    evalArgs,
-}
-
-// escaper collects type inferences about templates and changes needed to make
-// templates injection safe.
-type escaper struct {
-	// ns is the nameSpace that this escaper is associated with.
-	ns *nameSpace
-	// output[templateName] is the output context for a templateName that
-	// has been mangled to include its input context.
-	output map[string]context
-	// derived[c.mangle(name)] maps to a template derived from the template
-	// named name templateName for the start context c.
-	derived map[string]*template.Template
-	// called[templateName] is a set of called mangled template names.
-	called map[string]bool
-	// xxxNodeEdits are the accumulated edits to apply during commit.
-	// Such edits are not applied immediately in case a template set
-	// executes a given template in different escaping contexts.
-	actionNodeEdits   map[*parse.ActionNode][]string
-	templateNodeEdits map[*parse.TemplateNode]string
-	textNodeEdits     map[*parse.TextNode][]byte
-	// rangeContext holds context about the current range loop.
-	rangeContext *rangeContext
-}
-
-// rangeContext holds information about the current range loop.
-type rangeContext struct {
-	outer     *rangeContext // outer loop
-	breaks    []context     // context at each break action
-	continues []context     // context at each continue action
-}
-
-// makeEscaper creates a blank escaper for the given set.
-func makeEscaper(n *nameSpace) escaper {
-	return escaper{
-		n,
-		map[string]context{},
-		map[string]*template.Template{},
-		map[string]bool{},
-		map[*parse.ActionNode][]string{},
-		map[*parse.TemplateNode]string{},
-		map[*parse.TextNode][]byte{},
-		nil,
-	}
-}
-
-// filterFailsafe is an innocuous word that is emitted in place of unsafe values
-// by sanitizer functions. It is not a keyword in any programming language,
-// contains no special characters, is not empty, and when it appears in output
-// it is distinct enough that a developer can find the source of the problem
-// via a search engine.
-const filterFailsafe = "ZgotmplZ"
-
-// escape escapes a template node.
-func (e *escaper) escape(c context, n parse.Node) context {
-	switch n := n.(type) {
-	case *parse.ActionNode:
-		return e.escapeAction(c, n)
-	case *parse.BreakNode:
-		c.n = n
-		e.rangeContext.breaks = append(e.rangeContext.breaks, c)
-		return context{state: stateDead}
-	case *parse.CommentNode:
-		return c
-	case *parse.ContinueNode:
-		c.n = n
-		e.rangeContext.continues = append(e.rangeContext.breaks, c)
-		return context{state: stateDead}
-	case *parse.IfNode:
-		return e.escapeBranch(c, &n.BranchNode, "if")
-	case *parse.ListNode:
-		return e.escapeList(c, n)
-	case *parse.RangeNode:
-		return e.escapeBranch(c, &n.BranchNode, "range")
-	case *parse.TemplateNode:
-		return e.escapeTemplate(c, n)
-	case *parse.TextNode:
-		return e.escapeText(c, n)
-	case *parse.WithNode:
-		return e.escapeBranch(c, &n.BranchNode, "with")
-	}
-	panic("escaping " + n.String() + " is unimplemented")
-}
-
-// escapeAction escapes an action template node.
-func (e *escaper) escapeAction(c context, n *parse.ActionNode) context {
-	if len(n.Pipe.Decl) != 0 {
-		// A local variable assignment, not an interpolation.
-		return c
-	}
-	c = nudge(c)
-	// Check for disallowed use of predefined escapers in the pipeline.
-	for pos, idNode := range n.Pipe.Cmds {
-		node, ok := idNode.Args[0].(*parse.IdentifierNode)
-		if !ok {
-			// A predefined escaper "esc" will never be found as an identifier in a
-			// Chain or Field node, since:
-			// - "esc.x ..." is invalid, since predefined escapers return strings, and
-			//   strings do not have methods, keys or fields.
-			// - "... .esc" is invalid, since predefined escapers are global functions,
-			//   not methods or fields of any types.
-			// Therefore, it is safe to ignore these two node types.
-			continue
-		}
-		ident := node.Ident
-		if _, ok := predefinedEscapers[ident]; ok {
-			if pos < len(n.Pipe.Cmds)-1 ||
-				c.state == stateAttr && c.delim == delimSpaceOrTagEnd && ident == "html" {
-				return context{
-					state: stateError,
-					err:   errorf(ErrPredefinedEscaper, n, n.Line, "predefined escaper %q disallowed in template", ident),
-				}
-			}
-		}
-	}
-	s := make([]string, 0, 3)
-	switch c.state {
-	case stateError:
-		return c
-	case stateURL, stateCSSDqStr, stateCSSSqStr, stateCSSDqURL, stateCSSSqURL, stateCSSURL:
-		switch c.urlPart {
-		case urlPartNone:
-			s = append(s, "_html_template_urlfilter")
-			fallthrough
-		case urlPartPreQuery:
-			switch c.state {
-			case stateCSSDqStr, stateCSSSqStr:
-				s = append(s, "_html_template_cssescaper")
-			default:
-				s = append(s, "_html_template_urlnormalizer")
-			}
-		case urlPartQueryOrFrag:
-			s = append(s, "_html_template_urlescaper")
-		case urlPartUnknown:
-			return context{
-				state: stateError,
-				err:   errorf(ErrAmbigContext, n, n.Line, "%s appears in an ambiguous context within a URL", n),
-			}
-		default:
-			panic(c.urlPart.String())
-		}
-	case stateJS:
-		s = append(s, "_html_template_jsvalescaper")
-		// A slash after a value starts a div operator.
-		c.jsCtx = jsCtxDivOp
-	case stateJSDqStr, stateJSSqStr:
-		s = append(s, "_html_template_jsstrescaper")
-	case stateJSRegexp:
-		s = append(s, "_html_template_jsregexpescaper")
-	case stateCSS:
-		s = append(s, "_html_template_cssvaluefilter")
-	case stateText:
-		s = append(s, "_html_template_htmlescaper")
-	case stateRCDATA:
-		s = append(s, "_html_template_rcdataescaper")
-	case stateAttr:
-		// Handled below in delim check.
-	case stateAttrName, stateTag:
-		c.state = stateAttrName
-		s = append(s, "_html_template_htmlnamefilter")
-	case stateSrcset:
-		s = append(s, "_html_template_srcsetescaper")
-	default:
-		if isComment(c.state) {
-			s = append(s, "_html_template_commentescaper")
-		} else {
-			panic("unexpected state " + c.state.String())
-		}
-	}
-	switch c.delim {
-	case delimNone:
-		// No extra-escaping needed for raw text content.
-	case delimSpaceOrTagEnd:
-		s = append(s, "_html_template_nospaceescaper")
-	default:
-		s = append(s, "_html_template_attrescaper")
-	}
-	e.editActionNode(n, s)
-	return c
-}
-
-// ensurePipelineContains ensures that the pipeline ends with the commands with
-// the identifiers in s in order. If the pipeline ends with a predefined escaper
-// (i.e. "html" or "urlquery"), merge it with the identifiers in s.
-func ensurePipelineContains(p *parse.PipeNode, s []string) {
-	if len(s) == 0 {
-		// Do not rewrite pipeline if we have no escapers to insert.
-		return
-	}
-	// Precondition: p.Cmds contains at most one predefined escaper and the
-	// escaper will be present at p.Cmds[len(p.Cmds)-1]. This precondition is
-	// always true because of the checks in escapeAction.
-	pipelineLen := len(p.Cmds)
-	if pipelineLen > 0 {
-		lastCmd := p.Cmds[pipelineLen-1]
-		if idNode, ok := lastCmd.Args[0].(*parse.IdentifierNode); ok {
-			if esc := idNode.Ident; predefinedEscapers[esc] {
-				// Pipeline ends with a predefined escaper.
-				if len(p.Cmds) == 1 && len(lastCmd.Args) > 1 {
-					// Special case: pipeline is of the form {{ esc arg1 arg2 ... argN }},
-					// where esc is the predefined escaper, and arg1...argN are its arguments.
-					// Convert this into the equivalent form
-					// {{ _eval_args_ arg1 arg2 ... argN | esc }}, so that esc can be easily
-					// merged with the escapers in s.
-					lastCmd.Args[0] = parse.NewIdentifier("_eval_args_").SetTree(nil).SetPos(lastCmd.Args[0].Position())
-					p.Cmds = appendCmd(p.Cmds, newIdentCmd(esc, p.Position()))
-					pipelineLen++
-				}
-				// If any of the commands in s that we are about to insert is equivalent
-				// to the predefined escaper, use the predefined escaper instead.
-				dup := false
-				for i, escaper := range s {
-					if escFnsEq(esc, escaper) {
-						s[i] = idNode.Ident
-						dup = true
-					}
-				}
-				if dup {
-					// The predefined escaper will already be inserted along with the
-					// escapers in s, so do not copy it to the rewritten pipeline.
-					pipelineLen--
-				}
-			}
-		}
-	}
-	// Rewrite the pipeline, creating the escapers in s at the end of the pipeline.
-	newCmds := make([]*parse.CommandNode, pipelineLen, pipelineLen+len(s))
-	insertedIdents := make(map[string]bool)
-	for i := 0; i < pipelineLen; i++ {
-		cmd := p.Cmds[i]
-		newCmds[i] = cmd
-		if idNode, ok := cmd.Args[0].(*parse.IdentifierNode); ok {
-			insertedIdents[normalizeEscFn(idNode.Ident)] = true
-		}
-	}
-	for _, name := range s {
-		if !insertedIdents[normalizeEscFn(name)] {
-			// When two templates share an underlying parse tree via the use of
-			// AddParseTree and one template is executed after the other, this check
-			// ensures that escapers that were already inserted into the pipeline on
-			// the first escaping pass do not get inserted again.
-			newCmds = appendCmd(newCmds, newIdentCmd(name, p.Position()))
-		}
-	}
-	p.Cmds = newCmds
-}
-
-// predefinedEscapers contains template predefined escapers that are equivalent
-// to some contextual escapers. Keep in sync with equivEscapers.
-var predefinedEscapers = map[string]bool{
-	"html":     true,
-	"urlquery": true,
-}
-
-// equivEscapers matches contextual escapers to equivalent predefined
-// template escapers.
-var equivEscapers = map[string]string{
-	// The following pairs of HTML escapers provide equivalent security
-	// guarantees, since they all escape '\000', '\'', '"', '&', '<', and '>'.
-	"_html_template_attrescaper":   "html",
-	"_html_template_htmlescaper":   "html",
-	"_html_template_rcdataescaper": "html",
-	// These two URL escapers produce URLs safe for embedding in a URL query by
-	// percent-encoding all the reserved characters specified in RFC 3986 Section
-	// 2.2
-	"_html_template_urlescaper": "urlquery",
-	// These two functions are not actually equivalent; urlquery is stricter as it
-	// escapes reserved characters (e.g. '#'), while _html_template_urlnormalizer
-	// does not. It is therefore only safe to replace _html_template_urlnormalizer
-	// with urlquery (this happens in ensurePipelineContains), but not the otherI've
-	// way around. We keep this entry around to preserve the behavior of templates
-	// written before Go 1.9, which might depend on this substitution taking place.
-	"_html_template_urlnormalizer": "urlquery",
-}
-
-// escFnsEq reports whether the two escaping functions are equivalent.
-func escFnsEq(a, b string) bool {
-	return normalizeEscFn(a) == normalizeEscFn(b)
-}
-
-// normalizeEscFn(a) is equal to normalizeEscFn(b) for any pair of names of
-// escaper functions a and b that are equivalent.
-func normalizeEscFn(e string) string {
-	if norm := equivEscapers[e]; norm != "" {
-		return norm
-	}
-	return e
-}
-
-// redundantFuncs[a][b] implies that funcMap[b](funcMap[a](x)) == funcMap[a](x)
-// for all x.
-var redundantFuncs = map[string]map[string]bool{
-	"_html_template_commentescaper": {
-		"_html_template_attrescaper":    true,
-		"_html_template_nospaceescaper": true,
-		"_html_template_htmlescaper":    true,
-	},
-	"_html_template_cssescaper": {
-		"_html_template_attrescaper": true,
-	},
-	"_html_template_jsregexpescaper": {
-		"_html_template_attrescaper": true,
-	},
-	"_html_template_jsstrescaper": {
-		"_html_template_attrescaper": true,
-	},
-	"_html_template_urlescaper": {
-		"_html_template_urlnormalizer": true,
-	},
-}
-
-// appendCmd appends the given command to the end of the command pipeline
-// unless it is redundant with the last command.
-func appendCmd(cmds []*parse.CommandNode, cmd *parse.CommandNode) []*parse.CommandNode {
-	if n := len(cmds); n != 0 {
-		last, okLast := cmds[n-1].Args[0].(*parse.IdentifierNode)
-		next, okNext := cmd.Args[0].(*parse.IdentifierNode)
-		if okLast && okNext && redundantFuncs[last.Ident][next.Ident] {
-			return cmds
-		}
-	}
-	return append(cmds, cmd)
-}
-
-// newIdentCmd produces a command containing a single identifier node.
-func newIdentCmd(identifier string, pos parse.Pos) *parse.CommandNode {
-	return &parse.CommandNode{
-		NodeType: parse.NodeCommand,
-		Args:     []parse.Node{parse.NewIdentifier(identifier).SetTree(nil).SetPos(pos)}, // TODO: SetTree.
-	}
-}
-
-// nudge returns the context that would result from following empty string
-// transitions from the input context.
-// For example, parsing:
-//     `<a href=`
-// will end in context{stateBeforeValue, attrURL}, but parsing one extra rune:
-//     `<a href=x`
-// will end in context{stateURL, delimSpaceOrTagEnd, ...}.
-// There are two transitions that happen when the 'x' is seen:
-// (1) Transition from a before-value state to a start-of-value state without
-//     consuming any character.
-// (2) Consume 'x' and transition past the first value character.
-// In this case, nudging produces the context after (1) happens.
-func nudge(c context) context {
-	switch c.state {
-	case stateTag:
-		// In `<foo {{.}}`, the action should emit an attribute.
-		c.state = stateAttrName
-	case stateBeforeValue:
-		// In `<foo bar={{.}}`, the action is an undelimited value.
-		c.state, c.delim, c.attr = attrStartStates[c.attr], delimSpaceOrTagEnd, attrNone
-	case stateAfterName:
-		// In `<foo bar {{.}}`, the action is an attribute name.
-		c.state, c.attr = stateAttrName, attrNone
-	}
-	return c
-}
-
-// join joins the two contexts of a branch template node. The result is an
-// error context if either of the input contexts are error contexts, or if the
-// input contexts differ.
-func join(a, b context, node parse.Node, nodeName string) context {
-	if a.state == stateError {
-		return a
-	}
-	if b.state == stateError {
-		return b
-	}
-	if a.state == stateDead {
-		return b
-	}
-	if b.state == stateDead {
-		return a
-	}
-	if a.eq(b) {
-		return a
-	}
-
-	c := a
-	c.urlPart = b.urlPart
-	if c.eq(b) {
-		// The contexts differ only by urlPart.
-		c.urlPart = urlPartUnknown
-		return c
-	}
-
-	c = a
-	c.jsCtx = b.jsCtx
-	if c.eq(b) {
-		// The contexts differ only by jsCtx.
-		c.jsCtx = jsCtxUnknown
-		return c
-	}
-
-	// Allow a nudged context to join with an unnudged one.
-	// This means that
-	//   <p title={{if .C}}{{.}}{{end}}
-	// ends in an unquoted value state even though the else branch
-	// ends in stateBeforeValue.
-	if c, d := nudge(a), nudge(b); !(c.eq(a) && d.eq(b)) {
-		if e := join(c, d, node, nodeName); e.state != stateError {
-			return e
-		}
-	}
-
-	return context{
-		state: stateError,
-		err:   errorf(ErrBranchEnd, node, 0, "{{%s}} branches end in different contexts: %v, %v", nodeName, a, b),
-	}
-}
-
-// escapeBranch escapes a branch template node: "if", "range" and "with".
-func (e *escaper) escapeBranch(c context, n *parse.BranchNode, nodeName string) context {
-	if nodeName == "range" {
-		e.rangeContext = &rangeContext{outer: e.rangeContext}
-	}
-	c0 := e.escapeList(c, n.List)
-	if nodeName == "range" {
-		if c0.state != stateError {
-			c0 = joinRange(c0, e.rangeContext)
-		}
-		e.rangeContext = e.rangeContext.outer
-		if c0.state == stateError {
-			return c0
-		}
-
-		// The "true" branch of a "range" node can execute multiple times.
-		// We check that executing n.List once results in the same context
-		// as executing n.List twice.
-		e.rangeContext = &rangeContext{outer: e.rangeContext}
-		c1, _ := e.escapeListConditionally(c0, n.List, nil)
-		c0 = join(c0, c1, n, nodeName)
-		if c0.state == stateError {
-			e.rangeContext = e.rangeContext.outer
-			// Make clear that this is a problem on loop re-entry
-			// since developers tend to overlook that branch when
-			// debugging templates.
-			c0.err.Line = n.Line
-			c0.err.Description = "on range loop re-entry: " + c0.err.Description
-			return c0
-		}
-		c0 = joinRange(c0, e.rangeContext)
-		e.rangeContext = e.rangeContext.outer
-		if c0.state == stateError {
-			return c0
-		}
-	}
-	c1 := e.escapeList(c, n.ElseList)
-	return join(c0, c1, n, nodeName)
-}
-
-func joinRange(c0 context, rc *rangeContext) context {
-	// Merge contexts at break and continue statements into overall body context.
-	// In theory we could treat breaks differently from continues, but for now it is
-	// enough to treat them both as going back to the start of the loop (which may then stop).
-	for _, c := range rc.breaks {
-		c0 = join(c0, c, c.n, "range")
-		if c0.state == stateError {
-			c0.err.Line = c.n.(*parse.BreakNode).Line
-			c0.err.Description = "at range loop break: " + c0.err.Description
-			return c0
-		}
-	}
-	for _, c := range rc.continues {
-		c0 = join(c0, c, c.n, "range")
-		if c0.state == stateError {
-			c0.err.Line = c.n.(*parse.ContinueNode).Line
-			c0.err.Description = "at range loop continue: " + c0.err.Description
-			return c0
-		}
-	}
-	return c0
-}
-
-// escapeList escapes a list template node.
-func (e *escaper) escapeList(c context, n *parse.ListNode) context {
-	if n == nil {
-		return c
-	}
-	for _, m := range n.Nodes {
-		c = e.escape(c, m)
-		if c.state == stateDead {
-			break
-		}
-	}
-	return c
-}
-
-// escapeListConditionally escapes a list node but only preserves edits and
-// inferences in e if the inferences and output context satisfy filter.
-// It returns the best guess at an output context, and the result of the filter
-// which is the same as whether e was updated.
-func (e *escaper) escapeListConditionally(c context, n *parse.ListNode, filter func(*escaper, context) bool) (context, bool) {
-	e1 := makeEscaper(e.ns)
-	e1.rangeContext = e.rangeContext
-	// Make type inferences available to f.
-	for k, v := range e.output {
-		e1.output[k] = v
-	}
-	c = e1.escapeList(c, n)
-	ok := filter != nil && filter(&e1, c)
-	if ok {
-		// Copy inferences and edits from e1 back into e.
-		for k, v := range e1.output {
-			e.output[k] = v
-		}
-		for k, v := range e1.derived {
-			e.derived[k] = v
-		}
-		for k, v := range e1.called {
-			e.called[k] = v
-		}
-		for k, v := range e1.actionNodeEdits {
-			e.editActionNode(k, v)
-		}
-		for k, v := range e1.templateNodeEdits {
-			e.editTemplateNode(k, v)
-		}
-		for k, v := range e1.textNodeEdits {
-			e.editTextNode(k, v)
-		}
-	}
-	return c, ok
-}
-
-// escapeTemplate escapes a {{template}} call node.
-func (e *escaper) escapeTemplate(c context, n *parse.TemplateNode) context {
-	c, name := e.escapeTree(c, n, n.Name, n.Line)
-	if name != n.Name {
-		e.editTemplateNode(n, name)
-	}
-	return c
-}
-
-// escapeTree escapes the named template starting in the given context as
-// necessary and returns its output context.
-func (e *escaper) escapeTree(c context, node parse.Node, name string, line int) (context, string) {
-	// Mangle the template name with the input context to produce a reliable
-	// identifier.
-	dname := c.mangle(name)
-	e.called[dname] = true
-	if out, ok := e.output[dname]; ok {
-		// Already escaped.
-		return out, dname
-	}
-	t := e.template(name)
-	if t == nil {
-		// Two cases: The template exists but is empty, or has never been mentioned at
-		// all. Distinguish the cases in the error messages.
-		if e.ns.set[name] != nil {
-			return context{
-				state: stateError,
-				err:   errorf(ErrNoSuchTemplate, node, line, "%q is an incomplete or empty template", name),
-			}, dname
-		}
-		return context{
-			state: stateError,
-			err:   errorf(ErrNoSuchTemplate, node, line, "no such template %q", name),
-		}, dname
-	}
-	if dname != name {
-		// Use any template derived during an earlier call to escapeTemplate
-		// with different top level templates, or clone if necessary.
-		dt := e.template(dname)
-		if dt == nil {
-			dt = template.New(dname)
-			dt.Tree = &parse.Tree{Name: dname, Root: t.Root.CopyList()}
-			e.derived[dname] = dt
-		}
-		t = dt
-	}
-	return e.computeOutCtx(c, t), dname
-}
-
-// computeOutCtx takes a template and its start context and computes the output
-// context while storing any inferences in e.
-func (e *escaper) computeOutCtx(c context, t *template.Template) context {
-	// Propagate context over the body.
-	c1, ok := e.escapeTemplateBody(c, t)
-	if !ok {
-		// Look for a fixed point by assuming c1 as the output context.
-		if c2, ok2 := e.escapeTemplateBody(c1, t); ok2 {
-			c1, ok = c2, true
-		}
-		// Use c1 as the error context if neither assumption worked.
-	}
-	if !ok && c1.state != stateError {
-		return context{
-			state: stateError,
-			err:   errorf(ErrOutputContext, t.Tree.Root, 0, "cannot compute output context for template %s", t.Name()),
-		}
-	}
-	return c1
-}
-
-// escapeTemplateBody escapes the given template assuming the given output
-// context, and returns the best guess at the output context and whether the
-// assumption was correct.
-func (e *escaper) escapeTemplateBody(c context, t *template.Template) (context, bool) {
-	filter := func(e1 *escaper, c1 context) bool {
-		if c1.state == stateError {
-			// Do not update the input escaper, e.
-			return false
-		}
-		if !e1.called[t.Name()] {
-			// If t is not recursively called, then c1 is an
-			// accurate output context.
-			return true
-		}
-		// c1 is accurate if it matches our assumed output context.
-		return c.eq(c1)
-	}
-	// We need to assume an output context so that recursive template calls
-	// take the fast path out of escapeTree instead of infinitely recursing.
-	// Naively assuming that the input context is the same as the output
-	// works >90% of the time.
-	e.output[t.Name()] = c
-	return e.escapeListConditionally(c, t.Tree.Root, filter)
-}
-
-// delimEnds maps each delim to a string of characters that terminate it.
-var delimEnds = [...]string{
-	delimDoubleQuote: `"`,
-	delimSingleQuote: "'",
-	// Determined empirically by running the below in various browsers.
-	// var div = document.createElement("DIV");
-	// for (var i = 0; i < 0x10000; ++i) {
-	//   div.innerHTML = "<span title=x" + String.fromCharCode(i) + "-bar>";
-	//   if (div.getElementsByTagName("SPAN")[0].title.indexOf("bar") < 0)
-	//     document.write("<p>U+" + i.toString(16));
-	// }
-	delimSpaceOrTagEnd: " \t\n\f\r>",
-}
-
-var doctypeBytes = []byte("<!DOCTYPE")
-
-// escapeText escapes a text template node.
-func (e *escaper) escapeText(c context, n *parse.TextNode) context {
-	s, written, i, b := n.Text, 0, 0, new(bytes.Buffer)
-	for i != len(s) {
-		c1, nread := contextAfterText(c, s[i:])
-		i1 := i + nread
-		if c.state == stateText || c.state == stateRCDATA {
-			end := i1
-			if c1.state != c.state {
-				for j := end - 1; j >= i; j-- {
-					if s[j] == '<' {
-						end = j
-						break
-					}
-				}
-			}
-			for j := i; j < end; j++ {
-				if s[j] == '<' && !bytes.HasPrefix(bytes.ToUpper(s[j:]), doctypeBytes) {
-					b.Write(s[written:j])
-					b.WriteString("&lt;")
-					written = j + 1
-				}
-			}
-		} else if isComment(c.state) && c.delim == delimNone {
-			switch c.state {
-			case stateJSBlockCmt:
-				// https://es5.github.com/#x7.4:
-				// "Comments behave like white space and are
-				// discarded except that, if a MultiLineComment
-				// contains a line terminator character, then
-				// the entire comment is considered to be a
-				// LineTerminator for purposes of parsing by
-				// the syntactic grammar."
-				if bytes.ContainsAny(s[written:i1], "\n\r\u2028\u2029") {
-					b.WriteByte('\n')
-				} else {
-					b.WriteByte(' ')
-				}
-			case stateCSSBlockCmt:
-				b.WriteByte(' ')
-			}
-			written = i1
-		}
-		if c.state != c1.state && isComment(c1.state) && c1.delim == delimNone {
-			// Preserve the portion between written and the comment start.
-			cs := i1 - 2
-			if c1.state == stateHTMLCmt {
-				// "<!--" instead of "/*" or "//"
-				cs -= 2
-			}
-			b.Write(s[written:cs])
-			written = i1
-		}
-		if i == i1 && c.state == c1.state {
-			panic(fmt.Sprintf("infinite loop from %v to %v on %q..%q", c, c1, s[:i], s[i:]))
-		}
-		c, i = c1, i1
-	}
-
-	if written != 0 && c.state != stateError {
-		if !isComment(c.state) || c.delim != delimNone {
-			b.Write(n.Text[written:])
-		}
-		e.editTextNode(n, b.Bytes())
-	}
-	return c
-}
-
-// contextAfterText starts in context c, consumes some tokens from the front of
-// s, then returns the context after those tokens and the unprocessed suffix.
-func contextAfterText(c context, s []byte) (context, int) {
-	if c.delim == delimNone {
-		c1, i := tSpecialTagEnd(c, s)
-		if i == 0 {
-			// A special end tag (`</script>`) has been seen and
-			// all content preceding it has been consumed.
-			return c1, 0
-		}
-		// Consider all content up to any end tag.
-		return transitionFunc[c.state](c, s[:i])
-	}
-
-	// We are at the beginning of an attribute value.
-
-	i := bytes.IndexAny(s, delimEnds[c.delim])
-	if i == -1 {
-		i = len(s)
-	}
-	if c.delim == delimSpaceOrTagEnd {
-		// https://www.w3.org/TR/html5/syntax.html#attribute-value-(unquoted)-state
-		// lists the runes below as error characters.
-		// Error out because HTML parsers may differ on whether
-		// "<a id= onclick=f("     ends inside id's or onclick's value,
-		// "<a class=`foo "        ends inside a value,
-		// "<a style=font:'Arial'" needs open-quote fixup.
-		// IE treats '`' as a quotation character.
-		if j := bytes.IndexAny(s[:i], "\"'<=`"); j >= 0 {
-			return context{
-				state: stateError,
-				err:   errorf(ErrBadHTML, nil, 0, "%q in unquoted attr: %q", s[j:j+1], s[:i]),
-			}, len(s)
-		}
-	}
-	if i == len(s) {
-		// Remain inside the attribute.
-		// Decode the value so non-HTML rules can easily handle
-		//     <button onclick="alert(&quot;Hi!&quot;)">
-		// without having to entity decode token boundaries.
-		for u := []byte(html.UnescapeString(string(s))); len(u) != 0; {
-			c1, i1 := transitionFunc[c.state](c, u)
-			c, u = c1, u[i1:]
-		}
-		return c, len(s)
-	}
-
-	element := c.element
-
-	// If this is a non-JS "type" attribute inside "script" tag, do not treat the contents as JS.
-	if c.state == stateAttr && c.element == elementScript && c.attr == attrScriptType && !isJSType(string(s[:i])) {
-		element = elementNone
-	}
-
-	if c.delim != delimSpaceOrTagEnd {
-		// Consume any quote.
-		i++
-	}
-	// On exiting an attribute, we discard all state information
-	// except the state and element.
-	return context{state: stateTag, element: element}, i
-}
-
-// editActionNode records a change to an action pipeline for later commit.
-func (e *escaper) editActionNode(n *parse.ActionNode, cmds []string) {
-	if _, ok := e.actionNodeEdits[n]; ok {
-		panic(fmt.Sprintf("node %s shared between templates", n))
-	}
-	e.actionNodeEdits[n] = cmds
-}
-
-// editTemplateNode records a change to a {{template}} callee for later commit.
-func (e *escaper) editTemplateNode(n *parse.TemplateNode, callee string) {
-	if _, ok := e.templateNodeEdits[n]; ok {
-		panic(fmt.Sprintf("node %s shared between templates", n))
-	}
-	e.templateNodeEdits[n] = callee
-}
-
-// editTextNode records a change to a text node for later commit.
-func (e *escaper) editTextNode(n *parse.TextNode, text []byte) {
-	if _, ok := e.textNodeEdits[n]; ok {
-		panic(fmt.Sprintf("node %s shared between templates", n))
-	}
-	e.textNodeEdits[n] = text
-}
-
-// commit applies changes to actions and template calls needed to contextually
-// autoescape content and adds any derived templates to the set.
-func (e *escaper) commit() {
-	for name := range e.output {
-		e.template(name).Funcs(funcMap)
-	}
-	// Any template from the name space associated with this escaper can be used
-	// to add derived templates to the underlying text/template name space.
-	tmpl := e.arbitraryTemplate()
-	for _, t := range e.derived {
-		if _, err := tmpl.text.AddParseTree(t.Name(), t.Tree); err != nil {
-			panic("error adding derived template")
-		}
-	}
-	for n, s := range e.actionNodeEdits {
-		ensurePipelineContains(n.Pipe, s)
-	}
-	for n, name := range e.templateNodeEdits {
-		n.Name = name
-	}
-	for n, s := range e.textNodeEdits {
-		n.Text = s
-	}
-	// Reset state that is specific to this commit so that the same changes are
-	// not re-applied to the template on subsequent calls to commit.
-	e.called = make(map[string]bool)
-	e.actionNodeEdits = make(map[*parse.ActionNode][]string)
-	e.templateNodeEdits = make(map[*parse.TemplateNode]string)
-	e.textNodeEdits = make(map[*parse.TextNode][]byte)
-}
-
-// template returns the named template given a mangled template name.
-func (e *escaper) template(name string) *template.Template {
-	// Any template from the name space associated with this escaper can be used
-	// to look up templates in the underlying text/template name space.
-	t := e.arbitraryTemplate().text.Lookup(name)
-	if t == nil {
-		t = e.derived[name]
-	}
-	return t
-}
-
-// arbitraryTemplate returns an arbitrary template from the name space
-// associated with e and panics if no templates are found.
-func (e *escaper) arbitraryTemplate() *Template {
-	for _, t := range e.ns.set {
-		return t
-	}
-	panic("no templates in name space")
-}
-
-// Forwarding functions so that clients need only import this package
-// to reach the general escaping functions of text/template.
-
-// HTMLEscape writes to w the escaped HTML equivalent of the plain text data b.
-func HTMLEscape(w io.Writer, b []byte) {
-	template.HTMLEscape(w, b)
-}
-
-// HTMLEscapeString returns the escaped HTML equivalent of the plain text data s.
-func HTMLEscapeString(s string) string {
-	return template.HTMLEscapeString(s)
-}
-
-// HTMLEscaper returns the escaped HTML equivalent of the textual
-// representation of its arguments.
-func HTMLEscaper(args ...interface{}) string {
-	return template.HTMLEscaper(args...)
-}
-
-// JSEscape writes to w the escaped JavaScript equivalent of the plain text data b.
-func JSEscape(w io.Writer, b []byte) {
-	template.JSEscape(w, b)
-}
-
-// JSEscapeString returns the escaped JavaScript equivalent of the plain text data s.
-func JSEscapeString(s string) string {
-	return template.JSEscapeString(s)
-}
-
-// JSEscaper returns the escaped JavaScript equivalent of the textual
-// representation of its arguments.
-func JSEscaper(args ...interface{}) string {
-	return template.JSEscaper(args...)
-}
-
-// URLQueryEscaper returns the escaped value of the textual representation of
-// its arguments in a form suitable for embedding in a URL query.
-func URLQueryEscaper(args ...interface{}) string {
-	return template.URLQueryEscaper(args...)
-}
diff --git a/go.dev/cmd/internal/html/template/escape_test.go b/go.dev/cmd/internal/html/template/escape_test.go
deleted file mode 100644
index 8152ca2..0000000
--- a/go.dev/cmd/internal/html/template/escape_test.go
+++ /dev/null
@@ -1,1994 +0,0 @@
-// Copyright 2011 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 template
-
-import (
-	"bytes"
-	"encoding/json"
-	"fmt"
-	"os"
-	"strings"
-	"testing"
-
-	"golang.org/x/website/go.dev/cmd/internal/text/template"
-	"golang.org/x/website/go.dev/cmd/internal/text/template/parse"
-)
-
-type badMarshaler struct{}
-
-func (x *badMarshaler) MarshalJSON() ([]byte, error) {
-	// Keys in valid JSON must be double quoted as must all strings.
-	return []byte("{ foo: 'not quite valid JSON' }"), nil
-}
-
-type goodMarshaler struct{}
-
-func (x *goodMarshaler) MarshalJSON() ([]byte, error) {
-	return []byte(`{ "<foo>": "O'Reilly" }`), nil
-}
-
-func TestEscape(t *testing.T) {
-	data := struct {
-		F, T    bool
-		C, G, H string
-		A, E    []string
-		B, M    json.Marshaler
-		N       int
-		U       interface{} // untyped nil
-		Z       *int        // typed nil
-		W       HTML
-	}{
-		F: false,
-		T: true,
-		C: "<Cincinnati>",
-		G: "<Goodbye>",
-		H: "<Hello>",
-		A: []string{"<a>", "<b>"},
-		E: []string{},
-		N: 42,
-		B: &badMarshaler{},
-		M: &goodMarshaler{},
-		U: nil,
-		Z: nil,
-		W: HTML(`&iexcl;<b class="foo">Hello</b>, <textarea>O'World</textarea>!`),
-	}
-	pdata := &data
-
-	tests := []struct {
-		name   string
-		input  string
-		output string
-	}{
-		{
-			"if",
-			"{{if .T}}Hello{{end}}, {{.C}}!",
-			"Hello, &lt;Cincinnati&gt;!",
-		},
-		{
-			"else",
-			"{{if .F}}{{.H}}{{else}}{{.G}}{{end}}!",
-			"&lt;Goodbye&gt;!",
-		},
-		{
-			"overescaping1",
-			"Hello, {{.C | html}}!",
-			"Hello, &lt;Cincinnati&gt;!",
-		},
-		{
-			"overescaping2",
-			"Hello, {{html .C}}!",
-			"Hello, &lt;Cincinnati&gt;!",
-		},
-		{
-			"overescaping3",
-			"{{with .C}}{{$msg := .}}Hello, {{$msg}}!{{end}}",
-			"Hello, &lt;Cincinnati&gt;!",
-		},
-		{
-			"assignment",
-			"{{if $x := .H}}{{$x}}{{end}}",
-			"&lt;Hello&gt;",
-		},
-		{
-			"withBody",
-			"{{with .H}}{{.}}{{end}}",
-			"&lt;Hello&gt;",
-		},
-		{
-			"withElse",
-			"{{with .E}}{{.}}{{else}}{{.H}}{{end}}",
-			"&lt;Hello&gt;",
-		},
-		{
-			"rangeBody",
-			"{{range .A}}{{.}}{{end}}",
-			"&lt;a&gt;&lt;b&gt;",
-		},
-		{
-			"rangeElse",
-			"{{range .E}}{{.}}{{else}}{{.H}}{{end}}",
-			"&lt;Hello&gt;",
-		},
-		{
-			"nonStringValue",
-			"{{.T}}",
-			"true",
-		},
-		{
-			"untypedNilValue",
-			"{{.U}}",
-			"",
-		},
-		{
-			"typedNilValue",
-			"{{.Z}}",
-			"&lt;nil&gt;",
-		},
-		{
-			"constant",
-			`<a href="/search?q={{"'a<b'"}}">`,
-			`<a href="/search?q=%27a%3cb%27">`,
-		},
-		{
-			"multipleAttrs",
-			"<a b=1 c={{.H}}>",
-			"<a b=1 c=&lt;Hello&gt;>",
-		},
-		{
-			"urlStartRel",
-			`<a href='{{"/foo/bar?a=b&c=d"}}'>`,
-			`<a href='/foo/bar?a=b&amp;c=d'>`,
-		},
-		{
-			"urlStartAbsOk",
-			`<a href='{{"http://example.com/foo/bar?a=b&c=d"}}'>`,
-			`<a href='http://example.com/foo/bar?a=b&amp;c=d'>`,
-		},
-		{
-			"protocolRelativeURLStart",
-			`<a href='{{"//example.com:8000/foo/bar?a=b&c=d"}}'>`,
-			`<a href='//example.com:8000/foo/bar?a=b&amp;c=d'>`,
-		},
-		{
-			"pathRelativeURLStart",
-			`<a href="{{"/javascript:80/foo/bar"}}">`,
-			`<a href="/javascript:80/foo/bar">`,
-		},
-		{
-			"dangerousURLStart",
-			`<a href='{{"javascript:alert(%22pwned%22)"}}'>`,
-			`<a href='#ZgotmplZ'>`,
-		},
-		{
-			"dangerousURLStart2",
-			`<a href='  {{"javascript:alert(%22pwned%22)"}}'>`,
-			`<a href='  #ZgotmplZ'>`,
-		},
-		{
-			"nonHierURL",
-			`<a href={{"mailto:Muhammed \"The Greatest\" Ali <m.ali@example.com>"}}>`,
-			`<a href=mailto:Muhammed%20%22The%20Greatest%22%20Ali%20%3cm.ali@example.com%3e>`,
-		},
-		{
-			"urlPath",
-			`<a href='http://{{"javascript:80"}}/foo'>`,
-			`<a href='http://javascript:80/foo'>`,
-		},
-		{
-			"urlQuery",
-			`<a href='/search?q={{.H}}'>`,
-			`<a href='/search?q=%3cHello%3e'>`,
-		},
-		{
-			"urlFragment",
-			`<a href='/faq#{{.H}}'>`,
-			`<a href='/faq#%3cHello%3e'>`,
-		},
-		{
-			"urlBranch",
-			`<a href="{{if .F}}/foo?a=b{{else}}/bar{{end}}">`,
-			`<a href="/bar">`,
-		},
-		{
-			"urlBranchConflictMoot",
-			`<a href="{{if .T}}/foo?a={{else}}/bar#{{end}}{{.C}}">`,
-			`<a href="/foo?a=%3cCincinnati%3e">`,
-		},
-		{
-			"jsStrValue",
-			"<button onclick='alert({{.H}})'>",
-			`<button onclick='alert(&#34;\u003cHello\u003e&#34;)'>`,
-		},
-		{
-			"jsNumericValue",
-			"<button onclick='alert({{.N}})'>",
-			`<button onclick='alert( 42 )'>`,
-		},
-		{
-			"jsBoolValue",
-			"<button onclick='alert({{.T}})'>",
-			`<button onclick='alert( true )'>`,
-		},
-		{
-			"jsNilValueTyped",
-			"<button onclick='alert(typeof{{.Z}})'>",
-			`<button onclick='alert(typeof null )'>`,
-		},
-		{
-			"jsNilValueUntyped",
-			"<button onclick='alert(typeof{{.U}})'>",
-			`<button onclick='alert(typeof null )'>`,
-		},
-		{
-			"jsObjValue",
-			"<button onclick='alert({{.A}})'>",
-			`<button onclick='alert([&#34;\u003ca\u003e&#34;,&#34;\u003cb\u003e&#34;])'>`,
-		},
-		{
-			"jsObjValueScript",
-			"<script>alert({{.A}})</script>",
-			`<script>alert(["\u003ca\u003e","\u003cb\u003e"])</script>`,
-		},
-		{
-			"jsObjValueNotOverEscaped",
-			"<button onclick='alert({{.A | html}})'>",
-			`<button onclick='alert([&#34;\u003ca\u003e&#34;,&#34;\u003cb\u003e&#34;])'>`,
-		},
-		{
-			"jsStr",
-			"<button onclick='alert(&quot;{{.H}}&quot;)'>",
-			`<button onclick='alert(&quot;\u003cHello\u003e&quot;)'>`,
-		},
-		{
-			"badMarshaler",
-			`<button onclick='alert(1/{{.B}}in numbers)'>`,
-			`<button onclick='alert(1/ /* json: error calling MarshalJSON for type *template.badMarshaler: invalid character &#39;f&#39; looking for beginning of object key string */null in numbers)'>`,
-		},
-		{
-			"jsMarshaler",
-			`<button onclick='alert({{.M}})'>`,
-			`<button onclick='alert({&#34;\u003cfoo\u003e&#34;:&#34;O&#39;Reilly&#34;})'>`,
-		},
-		{
-			"jsStrNotUnderEscaped",
-			"<button onclick='alert({{.C | urlquery}})'>",
-			// URL escaped, then quoted for JS.
-			`<button onclick='alert(&#34;%3CCincinnati%3E&#34;)'>`,
-		},
-		{
-			"jsRe",
-			`<button onclick='alert(/{{"foo+bar"}}/.test(""))'>`,
-			`<button onclick='alert(/foo\u002bbar/.test(""))'>`,
-		},
-		{
-			"jsReBlank",
-			`<script>alert(/{{""}}/.test(""));</script>`,
-			`<script>alert(/(?:)/.test(""));</script>`,
-		},
-		{
-			"jsReAmbigOk",
-			`<script>{{if true}}var x = 1{{end}}</script>`,
-			// The {if} ends in an ambiguous jsCtx but there is
-			// no slash following so we shouldn't care.
-			`<script>var x = 1</script>`,
-		},
-		{
-			"styleBidiKeywordPassed",
-			`<p style="dir: {{"ltr"}}">`,
-			`<p style="dir: ltr">`,
-		},
-		{
-			"styleBidiPropNamePassed",
-			`<p style="border-{{"left"}}: 0; border-{{"right"}}: 1in">`,
-			`<p style="border-left: 0; border-right: 1in">`,
-		},
-		{
-			"styleExpressionBlocked",
-			`<p style="width: {{"expression(alert(1337))"}}">`,
-			`<p style="width: ZgotmplZ">`,
-		},
-		{
-			"styleTagSelectorPassed",
-			`<style>{{"p"}} { color: pink }</style>`,
-			`<style>p { color: pink }</style>`,
-		},
-		{
-			"styleIDPassed",
-			`<style>p{{"#my-ID"}} { font: Arial }</style>`,
-			`<style>p#my-ID { font: Arial }</style>`,
-		},
-		{
-			"styleClassPassed",
-			`<style>p{{".my_class"}} { font: Arial }</style>`,
-			`<style>p.my_class { font: Arial }</style>`,
-		},
-		{
-			"styleQuantityPassed",
-			`<a style="left: {{"2em"}}; top: {{0}}">`,
-			`<a style="left: 2em; top: 0">`,
-		},
-		{
-			"stylePctPassed",
-			`<table style=width:{{"100%"}}>`,
-			`<table style=width:100%>`,
-		},
-		{
-			"styleColorPassed",
-			`<p style="color: {{"#8ff"}}; background: {{"#000"}}">`,
-			`<p style="color: #8ff; background: #000">`,
-		},
-		{
-			"styleObfuscatedExpressionBlocked",
-			`<p style="width: {{"  e\\78preS\x00Sio/**/n(alert(1337))"}}">`,
-			`<p style="width: ZgotmplZ">`,
-		},
-		{
-			"styleMozBindingBlocked",
-			`<p style="{{"-moz-binding(alert(1337))"}}: ...">`,
-			`<p style="ZgotmplZ: ...">`,
-		},
-		{
-			"styleObfuscatedMozBindingBlocked",
-			`<p style="{{"  -mo\\7a-B\x00I/**/nding(alert(1337))"}}: ...">`,
-			`<p style="ZgotmplZ: ...">`,
-		},
-		{
-			"styleFontNameString",
-			`<p style='font-family: "{{"Times New Roman"}}"'>`,
-			`<p style='font-family: "Times New Roman"'>`,
-		},
-		{
-			"styleFontNameString",
-			`<p style='font-family: "{{"Times New Roman"}}", "{{"sans-serif"}}"'>`,
-			`<p style='font-family: "Times New Roman", "sans-serif"'>`,
-		},
-		{
-			"styleFontNameUnquoted",
-			`<p style='font-family: {{"Times New Roman"}}'>`,
-			`<p style='font-family: Times New Roman'>`,
-		},
-		{
-			"styleURLQueryEncoded",
-			`<p style="background: url(/img?name={{"O'Reilly Animal(1)<2>.png"}})">`,
-			`<p style="background: url(/img?name=O%27Reilly%20Animal%281%29%3c2%3e.png)">`,
-		},
-		{
-			"styleQuotedURLQueryEncoded",
-			`<p style="background: url('/img?name={{"O'Reilly Animal(1)<2>.png"}}')">`,
-			`<p style="background: url('/img?name=O%27Reilly%20Animal%281%29%3c2%3e.png')">`,
-		},
-		{
-			"styleStrQueryEncoded",
-			`<p style="background: '/img?name={{"O'Reilly Animal(1)<2>.png"}}'">`,
-			`<p style="background: '/img?name=O%27Reilly%20Animal%281%29%3c2%3e.png'">`,
-		},
-		{
-			"styleURLBadProtocolBlocked",
-			`<a style="background: url('{{"javascript:alert(1337)"}}')">`,
-			`<a style="background: url('#ZgotmplZ')">`,
-		},
-		{
-			"styleStrBadProtocolBlocked",
-			`<a style="background: '{{"vbscript:alert(1337)"}}'">`,
-			`<a style="background: '#ZgotmplZ'">`,
-		},
-		{
-			"styleStrEncodedProtocolEncoded",
-			`<a style="background: '{{"javascript\\3a alert(1337)"}}'">`,
-			// The CSS string 'javascript\\3a alert(1337)' does not contain a colon.
-			`<a style="background: 'javascript\\3a alert\28 1337\29 '">`,
-		},
-		{
-			"styleURLGoodProtocolPassed",
-			`<a style="background: url('{{"http://oreilly.com/O'Reilly Animals(1)<2>;{}.html"}}')">`,
-			`<a style="background: url('http://oreilly.com/O%27Reilly%20Animals%281%29%3c2%3e;%7b%7d.html')">`,
-		},
-		{
-			"styleStrGoodProtocolPassed",
-			`<a style="background: '{{"http://oreilly.com/O'Reilly Animals(1)<2>;{}.html"}}'">`,
-			`<a style="background: 'http\3a\2f\2foreilly.com\2fO\27Reilly Animals\28 1\29\3c 2\3e\3b\7b\7d.html'">`,
-		},
-		{
-			"styleURLEncodedForHTMLInAttr",
-			`<a style="background: url('{{"/search?img=foo&size=icon"}}')">`,
-			`<a style="background: url('/search?img=foo&amp;size=icon')">`,
-		},
-		{
-			"styleURLNotEncodedForHTMLInCdata",
-			`<style>body { background: url('{{"/search?img=foo&size=icon"}}') }</style>`,
-			`<style>body { background: url('/search?img=foo&size=icon') }</style>`,
-		},
-		{
-			"styleURLMixedCase",
-			`<p style="background: URL(#{{.H}})">`,
-			`<p style="background: URL(#%3cHello%3e)">`,
-		},
-		{
-			"stylePropertyPairPassed",
-			`<a style='{{"color: red"}}'>`,
-			`<a style='color: red'>`,
-		},
-		{
-			"styleStrSpecialsEncoded",
-			`<a style="font-family: '{{"/**/'\";:// \\"}}', &quot;{{"/**/'\";:// \\"}}&quot;">`,
-			`<a style="font-family: '\2f**\2f\27\22\3b\3a\2f\2f  \\', &quot;\2f**\2f\27\22\3b\3a\2f\2f  \\&quot;">`,
-		},
-		{
-			"styleURLSpecialsEncoded",
-			`<a style="border-image: url({{"/**/'\";:// \\"}}), url(&quot;{{"/**/'\";:// \\"}}&quot;), url('{{"/**/'\";:// \\"}}'), 'http://www.example.com/?q={{"/**/'\";:// \\"}}''">`,
-			`<a style="border-image: url(/**/%27%22;://%20%5c), url(&quot;/**/%27%22;://%20%5c&quot;), url('/**/%27%22;://%20%5c'), 'http://www.example.com/?q=%2f%2a%2a%2f%27%22%3b%3a%2f%2f%20%5c''">`,
-		},
-		{
-			"HTML comment",
-			"<b>Hello, <!-- name of world -->{{.C}}</b>",
-			"<b>Hello, &lt;Cincinnati&gt;</b>",
-		},
-		{
-			"HTML comment not first < in text node.",
-			"<<!-- -->!--",
-			"&lt;!--",
-		},
-		{
-			"HTML normalization 1",
-			"a < b",
-			"a &lt; b",
-		},
-		{
-			"HTML normalization 2",
-			"a << b",
-			"a &lt;&lt; b",
-		},
-		{
-			"HTML normalization 3",
-			"a<<!-- --><!-- -->b",
-			"a&lt;b",
-		},
-		{
-			"HTML doctype not normalized",
-			"<!DOCTYPE html>Hello, World!",
-			"<!DOCTYPE html>Hello, World!",
-		},
-		{
-			"HTML doctype not case-insensitive",
-			"<!doCtYPE htMl>Hello, World!",
-			"<!doCtYPE htMl>Hello, World!",
-		},
-		{
-			"No doctype injection",
-			`<!{{"DOCTYPE"}}`,
-			"&lt;!DOCTYPE",
-		},
-		{
-			"Split HTML comment",
-			"<b>Hello, <!-- name of {{if .T}}city -->{{.C}}{{else}}world -->{{.W}}{{end}}</b>",
-			"<b>Hello, &lt;Cincinnati&gt;</b>",
-		},
-		{
-			"JS line comment",
-			"<script>for (;;) { if (c()) break// foo not a label\n" +
-				"foo({{.T}});}</script>",
-			"<script>for (;;) { if (c()) break\n" +
-				"foo( true );}</script>",
-		},
-		{
-			"JS multiline block comment",
-			"<script>for (;;) { if (c()) break/* foo not a label\n" +
-				" */foo({{.T}});}</script>",
-			// Newline separates break from call. If newline
-			// removed, then break will consume label leaving
-			// code invalid.
-			"<script>for (;;) { if (c()) break\n" +
-				"foo( true );}</script>",
-		},
-		{
-			"JS single-line block comment",
-			"<script>for (;;) {\n" +
-				"if (c()) break/* foo a label */foo;" +
-				"x({{.T}});}</script>",
-			// Newline separates break from call. If newline
-			// removed, then break will consume label leaving
-			// code invalid.
-			"<script>for (;;) {\n" +
-				"if (c()) break foo;" +
-				"x( true );}</script>",
-		},
-		{
-			"JS block comment flush with mathematical division",
-			"<script>var a/*b*//c\nd</script>",
-			"<script>var a /c\nd</script>",
-		},
-		{
-			"JS mixed comments",
-			"<script>var a/*b*///c\nd</script>",
-			"<script>var a \nd</script>",
-		},
-		{
-			"CSS comments",
-			"<style>p// paragraph\n" +
-				`{border: 1px/* color */{{"#00f"}}}</style>`,
-			"<style>p\n" +
-				"{border: 1px #00f}</style>",
-		},
-		{
-			"JS attr block comment",
-			`<a onclick="f(&quot;&quot;); /* alert({{.H}}) */">`,
-			// Attribute comment tests should pass if the comments
-			// are successfully elided.
-			`<a onclick="f(&quot;&quot;); /* alert() */">`,
-		},
-		{
-			"JS attr line comment",
-			`<a onclick="// alert({{.G}})">`,
-			`<a onclick="// alert()">`,
-		},
-		{
-			"CSS attr block comment",
-			`<a style="/* color: {{.H}} */">`,
-			`<a style="/* color:  */">`,
-		},
-		{
-			"CSS attr line comment",
-			`<a style="// color: {{.G}}">`,
-			`<a style="// color: ">`,
-		},
-		{
-			"HTML substitution commented out",
-			"<p><!-- {{.H}} --></p>",
-			"<p></p>",
-		},
-		{
-			"Comment ends flush with start",
-			"<!--{{.}}--><script>/*{{.}}*///{{.}}\n</script><style>/*{{.}}*///{{.}}\n</style><a onclick='/*{{.}}*///{{.}}' style='/*{{.}}*///{{.}}'>",
-			"<script> \n</script><style> \n</style><a onclick='/**///' style='/**///'>",
-		},
-		{
-			"typed HTML in text",
-			`{{.W}}`,
-			`&iexcl;<b class="foo">Hello</b>, <textarea>O'World</textarea>!`,
-		},
-		{
-			"typed HTML in attribute",
-			`<div title="{{.W}}">`,
-			`<div title="&iexcl;Hello, O&#39;World!">`,
-		},
-		{
-			"typed HTML in script",
-			`<button onclick="alert({{.W}})">`,
-			`<button onclick="alert(&#34;\u0026iexcl;\u003cb class=\&#34;foo\&#34;\u003eHello\u003c/b\u003e, \u003ctextarea\u003eO&#39;World\u003c/textarea\u003e!&#34;)">`,
-		},
-		{
-			"typed HTML in RCDATA",
-			`<textarea>{{.W}}</textarea>`,
-			`<textarea>&iexcl;&lt;b class=&#34;foo&#34;&gt;Hello&lt;/b&gt;, &lt;textarea&gt;O&#39;World&lt;/textarea&gt;!</textarea>`,
-		},
-		{
-			"range in textarea",
-			"<textarea>{{range .A}}{{.}}{{end}}</textarea>",
-			"<textarea>&lt;a&gt;&lt;b&gt;</textarea>",
-		},
-		{
-			"No tag injection",
-			`{{"10$"}}<{{"script src,evil.org/pwnd.js"}}...`,
-			`10$&lt;script src,evil.org/pwnd.js...`,
-		},
-		{
-			"No comment injection",
-			`<{{"!--"}}`,
-			`&lt;!--`,
-		},
-		{
-			"No RCDATA end tag injection",
-			`<textarea><{{"/textarea "}}...</textarea>`,
-			`<textarea>&lt;/textarea ...</textarea>`,
-		},
-		{
-			"optional attrs",
-			`<img class="{{"iconClass"}}"` +
-				`{{if .T}} id="{{"<iconId>"}}"{{end}}` +
-				// Double quotes inside if/else.
-				` src=` +
-				`{{if .T}}"?{{"<iconPath>"}}"` +
-				`{{else}}"images/cleardot.gif"{{end}}` +
-				// Missing space before title, but it is not a
-				// part of the src attribute.
-				`{{if .T}}title="{{"<title>"}}"{{end}}` +
-				// Quotes outside if/else.
-				` alt="` +
-				`{{if .T}}{{"<alt>"}}` +
-				`{{else}}{{if .F}}{{"<title>"}}{{end}}` +
-				`{{end}}"` +
-				`>`,
-			`<img class="iconClass" id="&lt;iconId&gt;" src="?%3ciconPath%3e"title="&lt;title&gt;" alt="&lt;alt&gt;">`,
-		},
-		{
-			"conditional valueless attr name",
-			`<input{{if .T}} checked{{end}} name=n>`,
-			`<input checked name=n>`,
-		},
-		{
-			"conditional dynamic valueless attr name 1",
-			`<input{{if .T}} {{"checked"}}{{end}} name=n>`,
-			`<input checked name=n>`,
-		},
-		{
-			"conditional dynamic valueless attr name 2",
-			`<input {{if .T}}{{"checked"}} {{end}}name=n>`,
-			`<input checked name=n>`,
-		},
-		{
-			"dynamic attribute name",
-			`<img on{{"load"}}="alert({{"loaded"}})">`,
-			// Treated as JS since quotes are inserted.
-			`<img onload="alert(&#34;loaded&#34;)">`,
-		},
-		{
-			"bad dynamic attribute name 1",
-			// Allow checked, selected, disabled, but not JS or
-			// CSS attributes.
-			`<input {{"onchange"}}="{{"doEvil()"}}">`,
-			`<input ZgotmplZ="doEvil()">`,
-		},
-		{
-			"bad dynamic attribute name 2",
-			`<div {{"sTyle"}}="{{"color: expression(alert(1337))"}}">`,
-			`<div ZgotmplZ="color: expression(alert(1337))">`,
-		},
-		{
-			"bad dynamic attribute name 3",
-			// Allow title or alt, but not a URL.
-			`<img {{"src"}}="{{"javascript:doEvil()"}}">`,
-			`<img ZgotmplZ="javascript:doEvil()">`,
-		},
-		{
-			"bad dynamic attribute name 4",
-			// Structure preservation requires values to associate
-			// with a consistent attribute.
-			`<input checked {{""}}="Whose value am I?">`,
-			`<input checked ZgotmplZ="Whose value am I?">`,
-		},
-		{
-			"dynamic element name",
-			`<h{{3}}><table><t{{"head"}}>...</h{{3}}>`,
-			`<h3><table><thead>...</h3>`,
-		},
-		{
-			"bad dynamic element name",
-			// Dynamic element names are typically used to switch
-			// between (thead, tfoot, tbody), (ul, ol), (th, td),
-			// and other replaceable sets.
-			// We do not currently easily support (ul, ol).
-			// If we do change to support that, this test should
-			// catch failures to filter out special tag names which
-			// would violate the structure preservation property --
-			// if any special tag name could be substituted, then
-			// the content could be raw text/RCDATA for some inputs
-			// and regular HTML content for others.
-			`<{{"script"}}>{{"doEvil()"}}</{{"script"}}>`,
-			`&lt;script>doEvil()&lt;/script>`,
-		},
-		{
-			"srcset bad URL in second position",
-			`<img srcset="{{"/not-an-image#,javascript:alert(1)"}}">`,
-			// The second URL is also filtered.
-			`<img srcset="/not-an-image#,#ZgotmplZ">`,
-		},
-		{
-			"srcset buffer growth",
-			`<img srcset={{",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"}}>`,
-			`<img srcset=,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,>`,
-		},
-	}
-
-	for _, test := range tests {
-		tmpl := New(test.name)
-		tmpl = Must(tmpl.Parse(test.input))
-		// Check for bug 6459: Tree field was not set in Parse.
-		if tmpl.Tree != tmpl.text.Tree {
-			t.Errorf("%s: tree not set properly", test.name)
-			continue
-		}
-		b := new(bytes.Buffer)
-		if err := tmpl.Execute(b, data); err != nil {
-			t.Errorf("%s: template execution failed: %s", test.name, err)
-			continue
-		}
-		if w, g := test.output, b.String(); w != g {
-			t.Errorf("%s: escaped output: want\n\t%q\ngot\n\t%q", test.name, w, g)
-			continue
-		}
-		b.Reset()
-		if err := tmpl.Execute(b, pdata); err != nil {
-			t.Errorf("%s: template execution failed for pointer: %s", test.name, err)
-			continue
-		}
-		if w, g := test.output, b.String(); w != g {
-			t.Errorf("%s: escaped output for pointer: want\n\t%q\ngot\n\t%q", test.name, w, g)
-			continue
-		}
-		if tmpl.Tree != tmpl.text.Tree {
-			t.Errorf("%s: tree mismatch", test.name)
-			continue
-		}
-	}
-}
-
-func TestEscapeMap(t *testing.T) {
-	data := map[string]string{
-		"html":     `<h1>Hi!</h1>`,
-		"urlquery": `http://www.foo.com/index.html?title=main`,
-	}
-	for _, test := range [...]struct {
-		desc, input, output string
-	}{
-		// covering issue 20323
-		{
-			"field with predefined escaper name 1",
-			`{{.html | print}}`,
-			`&lt;h1&gt;Hi!&lt;/h1&gt;`,
-		},
-		// covering issue 20323
-		{
-			"field with predefined escaper name 2",
-			`{{.urlquery | print}}`,
-			`http://www.foo.com/index.html?title=main`,
-		},
-	} {
-		tmpl := Must(New("").Parse(test.input))
-		b := new(bytes.Buffer)
-		if err := tmpl.Execute(b, data); err != nil {
-			t.Errorf("%s: template execution failed: %s", test.desc, err)
-			continue
-		}
-		if w, g := test.output, b.String(); w != g {
-			t.Errorf("%s: escaped output: want\n\t%q\ngot\n\t%q", test.desc, w, g)
-			continue
-		}
-	}
-}
-
-func TestEscapeSet(t *testing.T) {
-	type dataItem struct {
-		Children []*dataItem
-		X        string
-	}
-
-	data := dataItem{
-		Children: []*dataItem{
-			{X: "foo"},
-			{X: "<bar>"},
-			{
-				Children: []*dataItem{
-					{X: "baz"},
-				},
-			},
-		},
-	}
-
-	tests := []struct {
-		inputs map[string]string
-		want   string
-	}{
-		// The trivial set.
-		{
-			map[string]string{
-				"main": ``,
-			},
-			``,
-		},
-		// A template called in the start context.
-		{
-			map[string]string{
-				"main": `Hello, {{template "helper"}}!`,
-				// Not a valid top level HTML template.
-				// "<b" is not a full tag.
-				"helper": `{{"<World>"}}`,
-			},
-			`Hello, &lt;World&gt;!`,
-		},
-		// A template called in a context other than the start.
-		{
-			map[string]string{
-				"main": `<a onclick='a = {{template "helper"}};'>`,
-				// Not a valid top level HTML template.
-				// "<b" is not a full tag.
-				"helper": `{{"<a>"}}<b`,
-			},
-			`<a onclick='a = &#34;\u003ca\u003e&#34;<b;'>`,
-		},
-		// A recursive template that ends in its start context.
-		{
-			map[string]string{
-				"main": `{{range .Children}}{{template "main" .}}{{else}}{{.X}} {{end}}`,
-			},
-			`foo &lt;bar&gt; baz `,
-		},
-		// A recursive helper template that ends in its start context.
-		{
-			map[string]string{
-				"main":   `{{template "helper" .}}`,
-				"helper": `{{if .Children}}<ul>{{range .Children}}<li>{{template "main" .}}</li>{{end}}</ul>{{else}}{{.X}}{{end}}`,
-			},
-			`<ul><li>foo</li><li>&lt;bar&gt;</li><li><ul><li>baz</li></ul></li></ul>`,
-		},
-		// Co-recursive templates that end in its start context.
-		{
-			map[string]string{
-				"main":   `<blockquote>{{range .Children}}{{template "helper" .}}{{end}}</blockquote>`,
-				"helper": `{{if .Children}}{{template "main" .}}{{else}}{{.X}}<br>{{end}}`,
-			},
-			`<blockquote>foo<br>&lt;bar&gt;<br><blockquote>baz<br></blockquote></blockquote>`,
-		},
-		// A template that is called in two different contexts.
-		{
-			map[string]string{
-				"main":   `<button onclick="title='{{template "helper"}}'; ...">{{template "helper"}}</button>`,
-				"helper": `{{11}} of {{"<100>"}}`,
-			},
-			`<button onclick="title='11 of \u003c100\u003e'; ...">11 of &lt;100&gt;</button>`,
-		},
-		// A non-recursive template that ends in a different context.
-		// helper starts in jsCtxRegexp and ends in jsCtxDivOp.
-		{
-			map[string]string{
-				"main":   `<script>var x={{template "helper"}}/{{"42"}};</script>`,
-				"helper": "{{126}}",
-			},
-			`<script>var x= 126 /"42";</script>`,
-		},
-		// A recursive template that ends in a similar context.
-		{
-			map[string]string{
-				"main":      `<script>var x=[{{template "countdown" 4}}];</script>`,
-				"countdown": `{{.}}{{if .}},{{template "countdown" . | pred}}{{end}}`,
-			},
-			`<script>var x=[ 4 , 3 , 2 , 1 , 0 ];</script>`,
-		},
-		// A recursive template that ends in a different context.
-		/*
-			{
-				map[string]string{
-					"main":   `<a href="/foo{{template "helper" .}}">`,
-					"helper": `{{if .Children}}{{range .Children}}{{template "helper" .}}{{end}}{{else}}?x={{.X}}{{end}}`,
-				},
-				`<a href="/foo?x=foo?x=%3cbar%3e?x=baz">`,
-			},
-		*/
-	}
-
-	// pred is a template function that returns the predecessor of a
-	// natural number for testing recursive templates.
-	fns := FuncMap{"pred": func(a ...interface{}) (interface{}, error) {
-		if len(a) == 1 {
-			if i, _ := a[0].(int); i > 0 {
-				return i - 1, nil
-			}
-		}
-		return nil, fmt.Errorf("undefined pred(%v)", a)
-	}}
-
-	for _, test := range tests {
-		source := ""
-		for name, body := range test.inputs {
-			source += fmt.Sprintf("{{define %q}}%s{{end}} ", name, body)
-		}
-		tmpl, err := New("root").Funcs(fns).Parse(source)
-		if err != nil {
-			t.Errorf("error parsing %q: %v", source, err)
-			continue
-		}
-		var b bytes.Buffer
-
-		if err := tmpl.ExecuteTemplate(&b, "main", data); err != nil {
-			t.Errorf("%q executing %v", err.Error(), tmpl.Lookup("main"))
-			continue
-		}
-		if got := b.String(); test.want != got {
-			t.Errorf("want\n\t%q\ngot\n\t%q", test.want, got)
-		}
-	}
-
-}
-
-func TestErrors(t *testing.T) {
-	tests := []struct {
-		input string
-		err   string
-	}{
-		// Non-error cases.
-		{
-			"{{if .Cond}}<a>{{else}}<b>{{end}}",
-			"",
-		},
-		{
-			"{{if .Cond}}<a>{{end}}",
-			"",
-		},
-		{
-			"{{if .Cond}}{{else}}<b>{{end}}",
-			"",
-		},
-		{
-			"{{with .Cond}}<div>{{end}}",
-			"",
-		},
-		{
-			"{{range .Items}}<a>{{end}}",
-			"",
-		},
-		{
-			"<a href='/foo?{{range .Items}}&{{.K}}={{.V}}{{end}}'>",
-			"",
-		},
-		{
-			"{{range .Items}}<a{{if .X}}{{end}}>{{end}}",
-			"",
-		},
-		{
-			"{{range .Items}}<a{{if .X}}{{end}}>{{continue}}{{end}}",
-			"",
-		},
-		{
-			"{{range .Items}}<a{{if .X}}{{end}}>{{break}}{{end}}",
-			"",
-		},
-		{
-			"{{range .Items}}<a{{if .X}}{{end}}>{{if .X}}{{break}}{{end}}{{end}}",
-			"",
-		},
-		// Error cases.
-		{
-			"{{if .Cond}}<a{{end}}",
-			"z:1:5: {{if}} branches",
-		},
-		{
-			"{{if .Cond}}\n{{else}}\n<a{{end}}",
-			"z:1:5: {{if}} branches",
-		},
-		{
-			// Missing quote in the else branch.
-			`{{if .Cond}}<a href="foo">{{else}}<a href="bar>{{end}}`,
-			"z:1:5: {{if}} branches",
-		},
-		{
-			// Different kind of attribute: href implies a URL.
-			"<a {{if .Cond}}href='{{else}}title='{{end}}{{.X}}'>",
-			"z:1:8: {{if}} branches",
-		},
-		{
-			"\n{{with .X}}<a{{end}}",
-			"z:2:7: {{with}} branches",
-		},
-		{
-			"\n{{with .X}}<a>{{else}}<a{{end}}",
-			"z:2:7: {{with}} branches",
-		},
-		{
-			"{{range .Items}}<a{{end}}",
-			`z:1: on range loop re-entry: "<" in attribute name: "<a"`,
-		},
-		{
-			"\n{{range .Items}} x='<a{{end}}",
-			"z:2:8: on range loop re-entry: {{range}} branches",
-		},
-		{
-			"{{range .Items}}<a{{if .X}}{{break}}{{end}}>{{end}}",
-			"z:1:29: at range loop break: {{range}} branches end in different contexts",
-		},
-		{
-			"{{range .Items}}<a{{if .X}}{{continue}}{{end}}>{{end}}",
-			"z:1:29: at range loop continue: {{range}} branches end in different contexts",
-		},
-		{
-			"<a b=1 c={{.H}}",
-			"z: ends in a non-text context: {stateAttr delimSpaceOrTagEnd",
-		},
-		{
-			"<script>foo();",
-			"z: ends in a non-text context: {stateJS",
-		},
-		{
-			`<a href="{{if .F}}/foo?a={{else}}/bar/{{end}}{{.H}}">`,
-			"z:1:47: {{.H}} appears in an ambiguous context within a URL",
-		},
-		{
-			`<a onclick="alert('Hello \`,
-			`unfinished escape sequence in JS string: "Hello \\"`,
-		},
-		{
-			`<a onclick='alert("Hello\, World\`,
-			`unfinished escape sequence in JS string: "Hello\\, World\\"`,
-		},
-		{
-			`<a onclick='alert(/x+\`,
-			`unfinished escape sequence in JS string: "x+\\"`,
-		},
-		{
-			`<a onclick="/foo[\]/`,
-			`unfinished JS regexp charset: "foo[\\]/"`,
-		},
-		{
-			// It is ambiguous whether 1.5 should be 1\.5 or 1.5.
-			// Either `var x = 1/- 1.5 /i.test(x)`
-			// where `i.test(x)` is a method call of reference i,
-			// or `/-1\.5/i.test(x)` which is a method call on a
-			// case insensitive regular expression.
-			`<script>{{if false}}var x = 1{{end}}/-{{"1.5"}}/i.test(x)</script>`,
-			`'/' could start a division or regexp: "/-"`,
-		},
-		{
-			`{{template "foo"}}`,
-			"z:1:11: no such template \"foo\"",
-		},
-		{
-			`<div{{template "y"}}>` +
-				// Illegal starting in stateTag but not in stateText.
-				`{{define "y"}} foo<b{{end}}`,
-			`"<" in attribute name: " foo<b"`,
-		},
-		{
-			`<script>reverseList = [{{template "t"}}]</script>` +
-				// Missing " after recursive call.
-				`{{define "t"}}{{if .Tail}}{{template "t" .Tail}}{{end}}{{.Head}}",{{end}}`,
-			`: cannot compute output context for template t$htmltemplate_stateJS_elementScript`,
-		},
-		{
-			`<input type=button value=onclick=>`,
-			`html/template:z: "=" in unquoted attr: "onclick="`,
-		},
-		{
-			`<input type=button value= onclick=>`,
-			`html/template:z: "=" in unquoted attr: "onclick="`,
-		},
-		{
-			`<input type=button value= 1+1=2>`,
-			`html/template:z: "=" in unquoted attr: "1+1=2"`,
-		},
-		{
-			"<a class=`foo>",
-			"golang.org/x/website/go.dev/cmd/internal/html/template:z: \"`\" in unquoted attr: \"`foo\"",
-		},
-		{
-			`<a style=font:'Arial'>`,
-			`html/template:z: "'" in unquoted attr: "font:'Arial'"`,
-		},
-		{
-			`<a=foo>`,
-			`: expected space, attr name, or end of tag, but got "=foo>"`,
-		},
-		{
-			`Hello, {{. | urlquery | print}}!`,
-			// urlquery is disallowed if it is not the last command in the pipeline.
-			`predefined escaper "urlquery" disallowed in template`,
-		},
-		{
-			`Hello, {{. | html | print}}!`,
-			// html is disallowed if it is not the last command in the pipeline.
-			`predefined escaper "html" disallowed in template`,
-		},
-		{
-			`Hello, {{html . | print}}!`,
-			// A direct call to html is disallowed if it is not the last command in the pipeline.
-			`predefined escaper "html" disallowed in template`,
-		},
-		{
-			`<div class={{. | html}}>Hello<div>`,
-			// html is disallowed in a pipeline that is in an unquoted attribute context,
-			// even if it is the last command in the pipeline.
-			`predefined escaper "html" disallowed in template`,
-		},
-		{
-			`Hello, {{. | urlquery | html}}!`,
-			// html is allowed since it is the last command in the pipeline, but urlquery is not.
-			`predefined escaper "urlquery" disallowed in template`,
-		},
-	}
-	for _, test := range tests {
-		buf := new(bytes.Buffer)
-		tmpl, err := New("z").Parse(test.input)
-		if err != nil {
-			t.Errorf("input=%q: unexpected parse error %s\n", test.input, err)
-			continue
-		}
-		err = tmpl.Execute(buf, nil)
-		var got string
-		if err != nil {
-			got = err.Error()
-		}
-		if test.err == "" {
-			if got != "" {
-				t.Errorf("input=%q: unexpected error %q", test.input, got)
-			}
-			continue
-		}
-		if !strings.Contains(got, test.err) {
-			t.Errorf("input=%q: error\n\t%q\ndoes not contain expected string\n\t%q", test.input, got, test.err)
-			continue
-		}
-		// Check that we get the same error if we call Execute again.
-		if err := tmpl.Execute(buf, nil); err == nil || err.Error() != got {
-			t.Errorf("input=%q: unexpected error on second call %q", test.input, err)
-
-		}
-	}
-}
-
-func TestEscapeText(t *testing.T) {
-	tests := []struct {
-		input  string
-		output context
-	}{
-		{
-			``,
-			context{},
-		},
-		{
-			`Hello, World!`,
-			context{},
-		},
-		{
-			// An orphaned "<" is OK.
-			`I <3 Ponies!`,
-			context{},
-		},
-		{
-			`<a`,
-			context{state: stateTag},
-		},
-		{
-			`<a `,
-			context{state: stateTag},
-		},
-		{
-			`<a>`,
-			context{state: stateText},
-		},
-		{
-			`<a href`,
-			context{state: stateAttrName, attr: attrURL},
-		},
-		{
-			`<a on`,
-			context{state: stateAttrName, attr: attrScript},
-		},
-		{
-			`<a href `,
-			context{state: stateAfterName, attr: attrURL},
-		},
-		{
-			`<a style  =  `,
-			context{state: stateBeforeValue, attr: attrStyle},
-		},
-		{
-			`<a href=`,
-			context{state: stateBeforeValue, attr: attrURL},
-		},
-		{
-			`<a href=x`,
-			context{state: stateURL, delim: delimSpaceOrTagEnd, urlPart: urlPartPreQuery, attr: attrURL},
-		},
-		{
-			`<a href=x `,
-			context{state: stateTag},
-		},
-		{
-			`<a href=>`,
-			context{state: stateText},
-		},
-		{
-			`<a href=x>`,
-			context{state: stateText},
-		},
-		{
-			`<a href ='`,
-			context{state: stateURL, delim: delimSingleQuote, attr: attrURL},
-		},
-		{
-			`<a href=''`,
-			context{state: stateTag},
-		},
-		{
-			`<a href= "`,
-			context{state: stateURL, delim: delimDoubleQuote, attr: attrURL},
-		},
-		{
-			`<a href=""`,
-			context{state: stateTag},
-		},
-		{
-			`<a title="`,
-			context{state: stateAttr, delim: delimDoubleQuote},
-		},
-		{
-			`<a HREF='http:`,
-			context{state: stateURL, delim: delimSingleQuote, urlPart: urlPartPreQuery, attr: attrURL},
-		},
-		{
-			`<a Href='/`,
-			context{state: stateURL, delim: delimSingleQuote, urlPart: urlPartPreQuery, attr: attrURL},
-		},
-		{
-			`<a href='"`,
-			context{state: stateURL, delim: delimSingleQuote, urlPart: urlPartPreQuery, attr: attrURL},
-		},
-		{
-			`<a href="'`,
-			context{state: stateURL, delim: delimDoubleQuote, urlPart: urlPartPreQuery, attr: attrURL},
-		},
-		{
-			`<a href='&apos;`,
-			context{state: stateURL, delim: delimSingleQuote, urlPart: urlPartPreQuery, attr: attrURL},
-		},
-		{
-			`<a href="&quot;`,
-			context{state: stateURL, delim: delimDoubleQuote, urlPart: urlPartPreQuery, attr: attrURL},
-		},
-		{
-			`<a href="&#34;`,
-			context{state: stateURL, delim: delimDoubleQuote, urlPart: urlPartPreQuery, attr: attrURL},
-		},
-		{
-			`<a href=&quot;`,
-			context{state: stateURL, delim: delimSpaceOrTagEnd, urlPart: urlPartPreQuery, attr: attrURL},
-		},
-		{
-			`<img alt="1">`,
-			context{state: stateText},
-		},
-		{
-			`<img alt="1>"`,
-			context{state: stateTag},
-		},
-		{
-			`<img alt="1>">`,
-			context{state: stateText},
-		},
-		{
-			`<input checked type="checkbox"`,
-			context{state: stateTag},
-		},
-		{
-			`<a onclick="`,
-			context{state: stateJS, delim: delimDoubleQuote, attr: attrScript},
-		},
-		{
-			`<a onclick="//foo`,
-			context{state: stateJSLineCmt, delim: delimDoubleQuote, attr: attrScript},
-		},
-		{
-			"<a onclick='//\n",
-			context{state: stateJS, delim: delimSingleQuote, attr: attrScript},
-		},
-		{
-			"<a onclick='//\r\n",
-			context{state: stateJS, delim: delimSingleQuote, attr: attrScript},
-		},
-		{
-			"<a onclick='//\u2028",
-			context{state: stateJS, delim: delimSingleQuote, attr: attrScript},
-		},
-		{
-			`<a onclick="/*`,
-			context{state: stateJSBlockCmt, delim: delimDoubleQuote, attr: attrScript},
-		},
-		{
-			`<a onclick="/*/`,
-			context{state: stateJSBlockCmt, delim: delimDoubleQuote, attr: attrScript},
-		},
-		{
-			`<a onclick="/**/`,
-			context{state: stateJS, delim: delimDoubleQuote, attr: attrScript},
-		},
-		{
-			`<a onkeypress="&quot;`,
-			context{state: stateJSDqStr, delim: delimDoubleQuote, attr: attrScript},
-		},
-		{
-			`<a onclick='&quot;foo&quot;`,
-			context{state: stateJS, delim: delimSingleQuote, jsCtx: jsCtxDivOp, attr: attrScript},
-		},
-		{
-			`<a onclick=&#39;foo&#39;`,
-			context{state: stateJS, delim: delimSpaceOrTagEnd, jsCtx: jsCtxDivOp, attr: attrScript},
-		},
-		{
-			`<a onclick=&#39;foo`,
-			context{state: stateJSSqStr, delim: delimSpaceOrTagEnd, attr: attrScript},
-		},
-		{
-			`<a onclick="&quot;foo'`,
-			context{state: stateJSDqStr, delim: delimDoubleQuote, attr: attrScript},
-		},
-		{
-			`<a onclick="'foo&quot;`,
-			context{state: stateJSSqStr, delim: delimDoubleQuote, attr: attrScript},
-		},
-		{
-			`<A ONCLICK="'`,
-			context{state: stateJSSqStr, delim: delimDoubleQuote, attr: attrScript},
-		},
-		{
-			`<a onclick="/`,
-			context{state: stateJSRegexp, delim: delimDoubleQuote, attr: attrScript},
-		},
-		{
-			`<a onclick="'foo'`,
-			context{state: stateJS, delim: delimDoubleQuote, jsCtx: jsCtxDivOp, attr: attrScript},
-		},
-		{
-			`<a onclick="'foo\'`,
-			context{state: stateJSSqStr, delim: delimDoubleQuote, attr: attrScript},
-		},
-		{
-			`<a onclick="'foo\'`,
-			context{state: stateJSSqStr, delim: delimDoubleQuote, attr: attrScript},
-		},
-		{
-			`<a onclick="/foo/`,
-			context{state: stateJS, delim: delimDoubleQuote, jsCtx: jsCtxDivOp, attr: attrScript},
-		},
-		{
-			`<script>/foo/ /=`,
-			context{state: stateJS, element: elementScript},
-		},
-		{
-			`<a onclick="1 /foo`,
-			context{state: stateJS, delim: delimDoubleQuote, jsCtx: jsCtxDivOp, attr: attrScript},
-		},
-		{
-			`<a onclick="1 /*c*/ /foo`,
-			context{state: stateJS, delim: delimDoubleQuote, jsCtx: jsCtxDivOp, attr: attrScript},
-		},
-		{
-			`<a onclick="/foo[/]`,
-			context{state: stateJSRegexp, delim: delimDoubleQuote, attr: attrScript},
-		},
-		{
-			`<a onclick="/foo\/`,
-			context{state: stateJSRegexp, delim: delimDoubleQuote, attr: attrScript},
-		},
-		{
-			`<a onclick="/foo/`,
-			context{state: stateJS, delim: delimDoubleQuote, jsCtx: jsCtxDivOp, attr: attrScript},
-		},
-		{
-			`<input checked style="`,
-			context{state: stateCSS, delim: delimDoubleQuote, attr: attrStyle},
-		},
-		{
-			`<a style="//`,
-			context{state: stateCSSLineCmt, delim: delimDoubleQuote, attr: attrStyle},
-		},
-		{
-			`<a style="//</script>`,
-			context{state: stateCSSLineCmt, delim: delimDoubleQuote, attr: attrStyle},
-		},
-		{
-			"<a style='//\n",
-			context{state: stateCSS, delim: delimSingleQuote, attr: attrStyle},
-		},
-		{
-			"<a style='//\r",
-			context{state: stateCSS, delim: delimSingleQuote, attr: attrStyle},
-		},
-		{
-			`<a style="/*`,
-			context{state: stateCSSBlockCmt, delim: delimDoubleQuote, attr: attrStyle},
-		},
-		{
-			`<a style="/*/`,
-			context{state: stateCSSBlockCmt, delim: delimDoubleQuote, attr: attrStyle},
-		},
-		{
-			`<a style="/**/`,
-			context{state: stateCSS, delim: delimDoubleQuote, attr: attrStyle},
-		},
-		{
-			`<a style="background: '`,
-			context{state: stateCSSSqStr, delim: delimDoubleQuote, attr: attrStyle},
-		},
-		{
-			`<a style="background: &quot;`,
-			context{state: stateCSSDqStr, delim: delimDoubleQuote, attr: attrStyle},
-		},
-		{
-			`<a style="background: '/foo?img=`,
-			context{state: stateCSSSqStr, delim: delimDoubleQuote, urlPart: urlPartQueryOrFrag, attr: attrStyle},
-		},
-		{
-			`<a style="background: '/`,
-			context{state: stateCSSSqStr, delim: delimDoubleQuote, urlPart: urlPartPreQuery, attr: attrStyle},
-		},
-		{
-			`<a style="background: url(&#x22;/`,
-			context{state: stateCSSDqURL, delim: delimDoubleQuote, urlPart: urlPartPreQuery, attr: attrStyle},
-		},
-		{
-			`<a style="background: url('/`,
-			context{state: stateCSSSqURL, delim: delimDoubleQuote, urlPart: urlPartPreQuery, attr: attrStyle},
-		},
-		{
-			`<a style="background: url('/)`,
-			context{state: stateCSSSqURL, delim: delimDoubleQuote, urlPart: urlPartPreQuery, attr: attrStyle},
-		},
-		{
-			`<a style="background: url('/ `,
-			context{state: stateCSSSqURL, delim: delimDoubleQuote, urlPart: urlPartPreQuery, attr: attrStyle},
-		},
-		{
-			`<a style="background: url(/`,
-			context{state: stateCSSURL, delim: delimDoubleQuote, urlPart: urlPartPreQuery, attr: attrStyle},
-		},
-		{
-			`<a style="background: url( `,
-			context{state: stateCSSURL, delim: delimDoubleQuote, attr: attrStyle},
-		},
-		{
-			`<a style="background: url( /image?name=`,
-			context{state: stateCSSURL, delim: delimDoubleQuote, urlPart: urlPartQueryOrFrag, attr: attrStyle},
-		},
-		{
-			`<a style="background: url(x)`,
-			context{state: stateCSS, delim: delimDoubleQuote, attr: attrStyle},
-		},
-		{
-			`<a style="background: url('x'`,
-			context{state: stateCSS, delim: delimDoubleQuote, attr: attrStyle},
-		},
-		{
-			`<a style="background: url( x `,
-			context{state: stateCSS, delim: delimDoubleQuote, attr: attrStyle},
-		},
-		{
-			`<!-- foo`,
-			context{state: stateHTMLCmt},
-		},
-		{
-			`<!-->`,
-			context{state: stateHTMLCmt},
-		},
-		{
-			`<!--->`,
-			context{state: stateHTMLCmt},
-		},
-		{
-			`<!-- foo -->`,
-			context{state: stateText},
-		},
-		{
-			`<script`,
-			context{state: stateTag, element: elementScript},
-		},
-		{
-			`<script `,
-			context{state: stateTag, element: elementScript},
-		},
-		{
-			`<script src="foo.js" `,
-			context{state: stateTag, element: elementScript},
-		},
-		{
-			`<script src='foo.js' `,
-			context{state: stateTag, element: elementScript},
-		},
-		{
-			`<script type=text/javascript `,
-			context{state: stateTag, element: elementScript},
-		},
-		{
-			`<script>`,
-			context{state: stateJS, jsCtx: jsCtxRegexp, element: elementScript},
-		},
-		{
-			`<script>foo`,
-			context{state: stateJS, jsCtx: jsCtxDivOp, element: elementScript},
-		},
-		{
-			`<script>foo</script>`,
-			context{state: stateText},
-		},
-		{
-			`<script>foo</script><!--`,
-			context{state: stateHTMLCmt},
-		},
-		{
-			`<script>document.write("<p>foo</p>");`,
-			context{state: stateJS, element: elementScript},
-		},
-		{
-			`<script>document.write("<p>foo<\/script>");`,
-			context{state: stateJS, element: elementScript},
-		},
-		{
-			`<script>document.write("<script>alert(1)</script>");`,
-			context{state: stateText},
-		},
-		{
-			`<script type="golang.org/x/website/go.dev/cmd/internal/text/template">`,
-			context{state: stateText},
-		},
-		// covering issue 19968
-		{
-			`<script type="TEXT/JAVASCRIPT">`,
-			context{state: stateJS, element: elementScript},
-		},
-		// covering issue 19965
-		{
-			`<script TYPE="golang.org/x/website/go.dev/cmd/internal/text/template">`,
-			context{state: stateText},
-		},
-		{
-			`<script type="notjs">`,
-			context{state: stateText},
-		},
-		{
-			`<Script>`,
-			context{state: stateJS, element: elementScript},
-		},
-		{
-			`<SCRIPT>foo`,
-			context{state: stateJS, jsCtx: jsCtxDivOp, element: elementScript},
-		},
-		{
-			`<textarea>value`,
-			context{state: stateRCDATA, element: elementTextarea},
-		},
-		{
-			`<textarea>value</TEXTAREA>`,
-			context{state: stateText},
-		},
-		{
-			`<textarea name=html><b`,
-			context{state: stateRCDATA, element: elementTextarea},
-		},
-		{
-			`<title>value`,
-			context{state: stateRCDATA, element: elementTitle},
-		},
-		{
-			`<style>value`,
-			context{state: stateCSS, element: elementStyle},
-		},
-		{
-			`<a xlink:href`,
-			context{state: stateAttrName, attr: attrURL},
-		},
-		{
-			`<a xmlns`,
-			context{state: stateAttrName, attr: attrURL},
-		},
-		{
-			`<a xmlns:foo`,
-			context{state: stateAttrName, attr: attrURL},
-		},
-		{
-			`<a xmlnsxyz`,
-			context{state: stateAttrName},
-		},
-		{
-			`<a data-url`,
-			context{state: stateAttrName, attr: attrURL},
-		},
-		{
-			`<a data-iconUri`,
-			context{state: stateAttrName, attr: attrURL},
-		},
-		{
-			`<a data-urlItem`,
-			context{state: stateAttrName, attr: attrURL},
-		},
-		{
-			`<a g:`,
-			context{state: stateAttrName},
-		},
-		{
-			`<a g:url`,
-			context{state: stateAttrName, attr: attrURL},
-		},
-		{
-			`<a g:iconUri`,
-			context{state: stateAttrName, attr: attrURL},
-		},
-		{
-			`<a g:urlItem`,
-			context{state: stateAttrName, attr: attrURL},
-		},
-		{
-			`<a g:value`,
-			context{state: stateAttrName},
-		},
-		{
-			`<a svg:style='`,
-			context{state: stateCSS, delim: delimSingleQuote, attr: attrStyle},
-		},
-		{
-			`<svg:font-face`,
-			context{state: stateTag},
-		},
-		{
-			`<svg:a svg:onclick="`,
-			context{state: stateJS, delim: delimDoubleQuote, attr: attrScript},
-		},
-		{
-			`<svg:a svg:onclick="x()">`,
-			context{},
-		},
-	}
-
-	for _, test := range tests {
-		b, e := []byte(test.input), makeEscaper(nil)
-		c := e.escapeText(context{}, &parse.TextNode{NodeType: parse.NodeText, Text: b})
-		if !test.output.eq(c) {
-			t.Errorf("input %q: want context\n\t%v\ngot\n\t%v", test.input, test.output, c)
-			continue
-		}
-		if test.input != string(b) {
-			t.Errorf("input %q: text node was modified: want %q got %q", test.input, test.input, b)
-			continue
-		}
-	}
-}
-
-func TestEnsurePipelineContains(t *testing.T) {
-	tests := []struct {
-		input, output string
-		ids           []string
-	}{
-		{
-			"{{.X}}",
-			".X",
-			[]string{},
-		},
-		{
-			"{{.X | html}}",
-			".X | html",
-			[]string{},
-		},
-		{
-			"{{.X}}",
-			".X | html",
-			[]string{"html"},
-		},
-		{
-			"{{html .X}}",
-			"_eval_args_ .X | html | urlquery",
-			[]string{"html", "urlquery"},
-		},
-		{
-			"{{html .X .Y .Z}}",
-			"_eval_args_ .X .Y .Z | html | urlquery",
-			[]string{"html", "urlquery"},
-		},
-		{
-			"{{.X | print}}",
-			".X | print | urlquery",
-			[]string{"urlquery"},
-		},
-		{
-			"{{.X | print | urlquery}}",
-			".X | print | urlquery",
-			[]string{"urlquery"},
-		},
-		{
-			"{{.X | urlquery}}",
-			".X | html | urlquery",
-			[]string{"html", "urlquery"},
-		},
-		{
-			"{{.X | print 2 | .f 3}}",
-			".X | print 2 | .f 3 | urlquery | html",
-			[]string{"urlquery", "html"},
-		},
-		{
-			// covering issue 10801
-			"{{.X | println.x }}",
-			".X | println.x | urlquery | html",
-			[]string{"urlquery", "html"},
-		},
-		{
-			// covering issue 10801
-			"{{.X | (print 12 | println).x }}",
-			".X | (print 12 | println).x | urlquery | html",
-			[]string{"urlquery", "html"},
-		},
-		// The following test cases ensure that the merging of internal escapers
-		// with the predefined "html" and "urlquery" escapers is correct.
-		{
-			"{{.X | urlquery}}",
-			".X | _html_template_urlfilter | urlquery",
-			[]string{"_html_template_urlfilter", "_html_template_urlnormalizer"},
-		},
-		{
-			"{{.X | urlquery}}",
-			".X | urlquery | _html_template_urlfilter | _html_template_cssescaper",
-			[]string{"_html_template_urlfilter", "_html_template_cssescaper"},
-		},
-		{
-			"{{.X | urlquery}}",
-			".X | urlquery",
-			[]string{"_html_template_urlnormalizer"},
-		},
-		{
-			"{{.X | urlquery}}",
-			".X | urlquery",
-			[]string{"_html_template_urlescaper"},
-		},
-		{
-			"{{.X | html}}",
-			".X | html",
-			[]string{"_html_template_htmlescaper"},
-		},
-		{
-			"{{.X | html}}",
-			".X | html",
-			[]string{"_html_template_rcdataescaper"},
-		},
-	}
-	for i, test := range tests {
-		tmpl := template.Must(template.New("test").Parse(test.input))
-		action, ok := (tmpl.Tree.Root.Nodes[0].(*parse.ActionNode))
-		if !ok {
-			t.Errorf("First node is not an action: %s", test.input)
-			continue
-		}
-		pipe := action.Pipe
-		originalIDs := make([]string, len(test.ids))
-		copy(originalIDs, test.ids)
-		ensurePipelineContains(pipe, test.ids)
-		got := pipe.String()
-		if got != test.output {
-			t.Errorf("#%d: %s, %v: want\n\t%s\ngot\n\t%s", i, test.input, originalIDs, test.output, got)
-		}
-	}
-}
-
-func TestEscapeMalformedPipelines(t *testing.T) {
-	tests := []string{
-		"{{ 0 | $ }}",
-		"{{ 0 | $ | urlquery }}",
-		"{{ 0 | (nil) }}",
-		"{{ 0 | (nil) | html }}",
-	}
-	for _, test := range tests {
-		var b bytes.Buffer
-		tmpl, err := New("test").Parse(test)
-		if err != nil {
-			t.Errorf("failed to parse set: %q", err)
-		}
-		err = tmpl.Execute(&b, nil)
-		if err == nil {
-			t.Errorf("Expected error for %q", test)
-		}
-	}
-}
-
-func TestEscapeErrorsNotIgnorable(t *testing.T) {
-	var b bytes.Buffer
-	tmpl, _ := New("dangerous").Parse("<a")
-	err := tmpl.Execute(&b, nil)
-	if err == nil {
-		t.Errorf("Expected error")
-	} else if b.Len() != 0 {
-		t.Errorf("Emitted output despite escaping failure")
-	}
-}
-
-func TestEscapeSetErrorsNotIgnorable(t *testing.T) {
-	var b bytes.Buffer
-	tmpl, err := New("root").Parse(`{{define "t"}}<a{{end}}`)
-	if err != nil {
-		t.Errorf("failed to parse set: %q", err)
-	}
-	err = tmpl.ExecuteTemplate(&b, "t", nil)
-	if err == nil {
-		t.Errorf("Expected error")
-	} else if b.Len() != 0 {
-		t.Errorf("Emitted output despite escaping failure")
-	}
-}
-
-func TestRedundantFuncs(t *testing.T) {
-	inputs := []interface{}{
-		"\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f" +
-			"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" +
-			` !"#$%&'()*+,-./` +
-			`0123456789:;<=>?` +
-			`@ABCDEFGHIJKLMNO` +
-			`PQRSTUVWXYZ[\]^_` +
-			"`abcdefghijklmno" +
-			"pqrstuvwxyz{|}~\x7f" +
-			"\u00A0\u0100\u2028\u2029\ufeff\ufdec\ufffd\uffff\U0001D11E" +
-			"&amp;%22\\",
-		CSS(`a[href =~ "//example.com"]#foo`),
-		HTML(`Hello, <b>World</b> &amp;tc!`),
-		HTMLAttr(` dir="ltr"`),
-		JS(`c && alert("Hello, World!");`),
-		JSStr(`Hello, World & O'Reilly\x21`),
-		URL(`greeting=H%69&addressee=(World)`),
-	}
-
-	for n0, m := range redundantFuncs {
-		f0 := funcMap[n0].(func(...interface{}) string)
-		for n1 := range m {
-			f1 := funcMap[n1].(func(...interface{}) string)
-			for _, input := range inputs {
-				want := f0(input)
-				if got := f1(want); want != got {
-					t.Errorf("%s %s with %T %q: want\n\t%q,\ngot\n\t%q", n0, n1, input, input, want, got)
-				}
-			}
-		}
-	}
-}
-
-func TestIndirectPrint(t *testing.T) {
-	a := 3
-	ap := &a
-	b := "hello"
-	bp := &b
-	bpp := &bp
-	tmpl := Must(New("t").Parse(`{{.}}`))
-	var buf bytes.Buffer
-	err := tmpl.Execute(&buf, ap)
-	if err != nil {
-		t.Errorf("Unexpected error: %s", err)
-	} else if buf.String() != "3" {
-		t.Errorf(`Expected "3"; got %q`, buf.String())
-	}
-	buf.Reset()
-	err = tmpl.Execute(&buf, bpp)
-	if err != nil {
-		t.Errorf("Unexpected error: %s", err)
-	} else if buf.String() != "hello" {
-		t.Errorf(`Expected "hello"; got %q`, buf.String())
-	}
-}
-
-// This is a test for issue 3272.
-func TestEmptyTemplateHTML(t *testing.T) {
-	page := Must(New("page").ParseFiles(os.DevNull))
-	if err := page.ExecuteTemplate(os.Stdout, "page", "nothing"); err == nil {
-		t.Fatal("expected error")
-	}
-}
-
-type Issue7379 int
-
-func (Issue7379) SomeMethod(x int) string {
-	return fmt.Sprintf("<%d>", x)
-}
-
-// This is a test for issue 7379: type assertion error caused panic, and then
-// the code to handle the panic breaks escaping. It's hard to see the second
-// problem once the first is fixed, but its fix is trivial so we let that go. See
-// the discussion for issue 7379.
-func TestPipeToMethodIsEscaped(t *testing.T) {
-	tmpl := Must(New("x").Parse("<html>{{0 | .SomeMethod}}</html>\n"))
-	tryExec := func() string {
-		defer func() {
-			panicValue := recover()
-			if panicValue != nil {
-				t.Errorf("panicked: %v\n", panicValue)
-			}
-		}()
-		var b bytes.Buffer
-		tmpl.Execute(&b, Issue7379(0))
-		return b.String()
-	}
-	for i := 0; i < 3; i++ {
-		str := tryExec()
-		const expect = "<html>&lt;0&gt;</html>\n"
-		if str != expect {
-			t.Errorf("expected %q got %q", expect, str)
-		}
-	}
-}
-
-// Unlike text/template, html/template crashed if given an incomplete
-// template, that is, a template that had been named but not given any content.
-// This is issue #10204.
-func TestErrorOnUndefined(t *testing.T) {
-	tmpl := New("undefined")
-
-	err := tmpl.Execute(nil, nil)
-	if err == nil {
-		t.Error("expected error")
-	} else if !strings.Contains(err.Error(), "incomplete") {
-		t.Errorf("expected error about incomplete template; got %s", err)
-	}
-}
-
-// This covers issue #20842.
-func TestIdempotentExecute(t *testing.T) {
-	tmpl := Must(New("").
-		Parse(`{{define "main"}}<body>{{template "hello"}}</body>{{end}}`))
-	Must(tmpl.
-		Parse(`{{define "hello"}}Hello, {{"Ladies & Gentlemen!"}}{{end}}`))
-	got := new(bytes.Buffer)
-	var err error
-	// Ensure that "hello" produces the same output when executed twice.
-	want := "Hello, Ladies &amp; Gentlemen!"
-	for i := 0; i < 2; i++ {
-		err = tmpl.ExecuteTemplate(got, "hello", nil)
-		if err != nil {
-			t.Errorf("unexpected error: %s", err)
-		}
-		if got.String() != want {
-			t.Errorf("after executing template \"hello\", got:\n\t%q\nwant:\n\t%q\n", got.String(), want)
-		}
-		got.Reset()
-	}
-	// Ensure that the implicit re-execution of "hello" during the execution of
-	// "main" does not cause the output of "hello" to change.
-	err = tmpl.ExecuteTemplate(got, "main", nil)
-	if err != nil {
-		t.Errorf("unexpected error: %s", err)
-	}
-	// If the HTML escaper is added again to the action {{"Ladies & Gentlemen!"}},
-	// we would expected to see the ampersand overescaped to "&amp;amp;".
-	want = "<body>Hello, Ladies &amp; Gentlemen!</body>"
-	if got.String() != want {
-		t.Errorf("after executing template \"main\", got:\n\t%q\nwant:\n\t%q\n", got.String(), want)
-	}
-}
-
-func BenchmarkEscapedExecute(b *testing.B) {
-	tmpl := Must(New("t").Parse(`<a onclick="alert('{{.}}')">{{.}}</a>`))
-	var buf bytes.Buffer
-	b.ResetTimer()
-	for i := 0; i < b.N; i++ {
-		tmpl.Execute(&buf, "foo & 'bar' & baz")
-		buf.Reset()
-	}
-}
-
-// Covers issue 22780.
-func TestOrphanedTemplate(t *testing.T) {
-	t1 := Must(New("foo").Parse(`<a href="{{.}}">link1</a>`))
-	t2 := Must(t1.New("foo").Parse(`bar`))
-
-	var b bytes.Buffer
-	const wantError = `template: "foo" is an incomplete or empty template`
-	if err := t1.Execute(&b, "javascript:alert(1)"); err == nil {
-		t.Fatal("expected error executing t1")
-	} else if gotError := err.Error(); gotError != wantError {
-		t.Fatalf("got t1 execution error:\n\t%s\nwant:\n\t%s", gotError, wantError)
-	}
-	b.Reset()
-	if err := t2.Execute(&b, nil); err != nil {
-		t.Fatalf("error executing t2: %s", err)
-	}
-	const want = "bar"
-	if got := b.String(); got != want {
-		t.Fatalf("t2 rendered %q, want %q", got, want)
-	}
-}
-
-// Covers issue 21844.
-func TestAliasedParseTreeDoesNotOverescape(t *testing.T) {
-	const (
-		tmplText = `{{.}}`
-		data     = `<baz>`
-		want     = `&lt;baz&gt;`
-	)
-	// Templates "foo" and "bar" both alias the same underlying parse tree.
-	tpl := Must(New("foo").Parse(tmplText))
-	if _, err := tpl.AddParseTree("bar", tpl.Tree); err != nil {
-		t.Fatalf("AddParseTree error: %v", err)
-	}
-	var b1, b2 bytes.Buffer
-	if err := tpl.ExecuteTemplate(&b1, "foo", data); err != nil {
-		t.Fatalf(`ExecuteTemplate failed for "foo": %v`, err)
-	}
-	if err := tpl.ExecuteTemplate(&b2, "bar", data); err != nil {
-		t.Fatalf(`ExecuteTemplate failed for "foo": %v`, err)
-	}
-	got1, got2 := b1.String(), b2.String()
-	if got1 != want {
-		t.Fatalf(`Template "foo" rendered %q, want %q`, got1, want)
-	}
-	if got1 != got2 {
-		t.Fatalf(`Template "foo" and "bar" rendered %q and %q respectively, expected equal values`, got1, got2)
-	}
-}
diff --git a/go.dev/cmd/internal/html/template/example_test.go b/go.dev/cmd/internal/html/template/example_test.go
deleted file mode 100644
index 3ec1b60..0000000
--- a/go.dev/cmd/internal/html/template/example_test.go
+++ /dev/null
@@ -1,182 +0,0 @@
-// 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 template_test
-
-import (
-	"fmt"
-	"log"
-	"os"
-	"strings"
-
-	"golang.org/x/website/go.dev/cmd/internal/html/template"
-)
-
-func Example() {
-	const tpl = `
-<!DOCTYPE html>
-<html>
-	<head>
-		<meta charset="UTF-8">
-		<title>{{.Title}}</title>
-	</head>
-	<body>
-		{{range .Items}}<div>{{ . }}</div>{{else}}<div><strong>no rows</strong></div>{{end}}
-	</body>
-</html>`
-
-	check := func(err error) {
-		if err != nil {
-			log.Fatal(err)
-		}
-	}
-	t, err := template.New("webpage").Parse(tpl)
-	check(err)
-
-	data := struct {
-		Title string
-		Items []string
-	}{
-		Title: "My page",
-		Items: []string{
-			"My photos",
-			"My blog",
-		},
-	}
-
-	err = t.Execute(os.Stdout, data)
-	check(err)
-
-	noItems := struct {
-		Title string
-		Items []string
-	}{
-		Title: "My another page",
-		Items: []string{},
-	}
-
-	err = t.Execute(os.Stdout, noItems)
-	check(err)
-
-	// Output:
-	// <!DOCTYPE html>
-	// <html>
-	// 	<head>
-	// 		<meta charset="UTF-8">
-	// 		<title>My page</title>
-	// 	</head>
-	// 	<body>
-	// 		<div>My photos</div><div>My blog</div>
-	// 	</body>
-	// </html>
-	// <!DOCTYPE html>
-	// <html>
-	// 	<head>
-	// 		<meta charset="UTF-8">
-	// 		<title>My another page</title>
-	// 	</head>
-	// 	<body>
-	// 		<div><strong>no rows</strong></div>
-	// 	</body>
-	// </html>
-
-}
-
-func Example_autoescaping() {
-	check := func(err error) {
-		if err != nil {
-			log.Fatal(err)
-		}
-	}
-	t, err := template.New("foo").Parse(`{{define "T"}}Hello, {{.}}!{{end}}`)
-	check(err)
-	err = t.ExecuteTemplate(os.Stdout, "T", "<script>alert('you have been pwned')</script>")
-	check(err)
-	// Output:
-	// Hello, &lt;script&gt;alert(&#39;you have been pwned&#39;)&lt;/script&gt;!
-}
-
-func Example_escape() {
-	const s = `"Fran & Freddie's Diner" <tasty@example.com>`
-	v := []interface{}{`"Fran & Freddie's Diner"`, ' ', `<tasty@example.com>`}
-
-	fmt.Println(template.HTMLEscapeString(s))
-	template.HTMLEscape(os.Stdout, []byte(s))
-	fmt.Fprintln(os.Stdout, "")
-	fmt.Println(template.HTMLEscaper(v...))
-
-	fmt.Println(template.JSEscapeString(s))
-	template.JSEscape(os.Stdout, []byte(s))
-	fmt.Fprintln(os.Stdout, "")
-	fmt.Println(template.JSEscaper(v...))
-
-	fmt.Println(template.URLQueryEscaper(v...))
-
-	// Output:
-	// &#34;Fran &amp; Freddie&#39;s Diner&#34; &lt;tasty@example.com&gt;
-	// &#34;Fran &amp; Freddie&#39;s Diner&#34; &lt;tasty@example.com&gt;
-	// &#34;Fran &amp; Freddie&#39;s Diner&#34;32&lt;tasty@example.com&gt;
-	// \"Fran \u0026 Freddie\'s Diner\" \u003Ctasty@example.com\u003E
-	// \"Fran \u0026 Freddie\'s Diner\" \u003Ctasty@example.com\u003E
-	// \"Fran \u0026 Freddie\'s Diner\"32\u003Ctasty@example.com\u003E
-	// %22Fran+%26+Freddie%27s+Diner%2232%3Ctasty%40example.com%3E
-
-}
-
-func ExampleTemplate_Delims() {
-	const text = "<<.Greeting>> {{.Name}}"
-
-	data := struct {
-		Greeting string
-		Name     string
-	}{
-		Greeting: "Hello",
-		Name:     "Joe",
-	}
-
-	t := template.Must(template.New("tpl").Delims("<<", ">>").Parse(text))
-
-	err := t.Execute(os.Stdout, data)
-	if err != nil {
-		log.Fatal(err)
-	}
-
-	// Output:
-	// Hello {{.Name}}
-}
-
-// The following example is duplicated in text/template; keep them in sync.
-
-func ExampleTemplate_block() {
-	const (
-		master  = `Names:{{block "list" .}}{{"\n"}}{{range .}}{{println "-" .}}{{end}}{{end}}`
-		overlay = `{{define "list"}} {{join . ", "}}{{end}} `
-	)
-	var (
-		funcs     = template.FuncMap{"join": strings.Join}
-		guardians = []string{"Gamora", "Groot", "Nebula", "Rocket", "Star-Lord"}
-	)
-	masterTmpl, err := template.New("master").Funcs(funcs).Parse(master)
-	if err != nil {
-		log.Fatal(err)
-	}
-	overlayTmpl, err := template.Must(masterTmpl.Clone()).Parse(overlay)
-	if err != nil {
-		log.Fatal(err)
-	}
-	if err := masterTmpl.Execute(os.Stdout, guardians); err != nil {
-		log.Fatal(err)
-	}
-	if err := overlayTmpl.Execute(os.Stdout, guardians); err != nil {
-		log.Fatal(err)
-	}
-	// Output:
-	// Names:
-	// - Gamora
-	// - Groot
-	// - Nebula
-	// - Rocket
-	// - Star-Lord
-	// Names: Gamora, Groot, Nebula, Rocket, Star-Lord
-}
diff --git a/go.dev/cmd/internal/html/template/examplefiles_test.go b/go.dev/cmd/internal/html/template/examplefiles_test.go
deleted file mode 100644
index 1ff585d..0000000
--- a/go.dev/cmd/internal/html/template/examplefiles_test.go
+++ /dev/null
@@ -1,227 +0,0 @@
-// Copyright 2016 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 template_test
-
-import (
-	"io"
-	"io/ioutil"
-	"log"
-	"os"
-	"path/filepath"
-
-	"golang.org/x/website/go.dev/cmd/internal/text/template"
-)
-
-// templateFile defines the contents of a template to be stored in a file, for testing.
-type templateFile struct {
-	name     string
-	contents string
-}
-
-func createTestDir(files []templateFile) string {
-	dir, err := ioutil.TempDir("", "template")
-	if err != nil {
-		log.Fatal(err)
-	}
-	for _, file := range files {
-		f, err := os.Create(filepath.Join(dir, file.name))
-		if err != nil {
-			log.Fatal(err)
-		}
-		defer f.Close()
-		_, err = io.WriteString(f, file.contents)
-		if err != nil {
-			log.Fatal(err)
-		}
-	}
-	return dir
-}
-
-// The following example is duplicated in text/template; keep them in sync.
-
-// Here we demonstrate loading a set of templates from a directory.
-func ExampleTemplate_glob() {
-	// Here we create a temporary directory and populate it with our sample
-	// template definition files; usually the template files would already
-	// exist in some location known to the program.
-	dir := createTestDir([]templateFile{
-		// T0.tmpl is a plain template file that just invokes T1.
-		{"T0.tmpl", `T0 invokes T1: ({{template "T1"}})`},
-		// T1.tmpl defines a template, T1 that invokes T2.
-		{"T1.tmpl", `{{define "T1"}}T1 invokes T2: ({{template "T2"}}){{end}}`},
-		// T2.tmpl defines a template T2.
-		{"T2.tmpl", `{{define "T2"}}This is T2{{end}}`},
-	})
-	// Clean up after the test; another quirk of running as an example.
-	defer os.RemoveAll(dir)
-
-	// pattern is the glob pattern used to find all the template files.
-	pattern := filepath.Join(dir, "*.tmpl")
-
-	// Here starts the example proper.
-	// T0.tmpl is the first name matched, so it becomes the starting template,
-	// the value returned by ParseGlob.
-	tmpl := template.Must(template.ParseGlob(pattern))
-
-	err := tmpl.Execute(os.Stdout, nil)
-	if err != nil {
-		log.Fatalf("template execution: %s", err)
-	}
-	// Output:
-	// T0 invokes T1: (T1 invokes T2: (This is T2))
-}
-
-// Here we demonstrate loading a set of templates from files in different directories
-func ExampleTemplate_parsefiles() {
-	// Here we create different temporary directories and populate them with our sample
-	// template definition files; usually the template files would already
-	// exist in some location known to the program.
-	dir1 := createTestDir([]templateFile{
-		// T1.tmpl is a plain template file that just invokes T2.
-		{"T1.tmpl", `T1 invokes T2: ({{template "T2"}})`},
-	})
-
-	dir2 := createTestDir([]templateFile{
-		// T2.tmpl defines a template T2.
-		{"T2.tmpl", `{{define "T2"}}This is T2{{end}}`},
-	})
-
-	// Clean up after the test; another quirk of running as an example.
-	defer func(dirs ...string) {
-		for _, dir := range dirs {
-			os.RemoveAll(dir)
-		}
-	}(dir1, dir2)
-
-	// Here starts the example proper.
-	// Let's just parse only dir1/T0 and dir2/T2
-	paths := []string{
-		filepath.Join(dir1, "T1.tmpl"),
-		filepath.Join(dir2, "T2.tmpl"),
-	}
-	tmpl := template.Must(template.ParseFiles(paths...))
-
-	err := tmpl.Execute(os.Stdout, nil)
-	if err != nil {
-		log.Fatalf("template execution: %s", err)
-	}
-	// Output:
-	// T1 invokes T2: (This is T2)
-}
-
-// The following example is duplicated in text/template; keep them in sync.
-
-// This example demonstrates one way to share some templates
-// and use them in different contexts. In this variant we add multiple driver
-// templates by hand to an existing bundle of templates.
-func ExampleTemplate_helpers() {
-	// Here we create a temporary directory and populate it with our sample
-	// template definition files; usually the template files would already
-	// exist in some location known to the program.
-	dir := createTestDir([]templateFile{
-		// T1.tmpl defines a template, T1 that invokes T2.
-		{"T1.tmpl", `{{define "T1"}}T1 invokes T2: ({{template "T2"}}){{end}}`},
-		// T2.tmpl defines a template T2.
-		{"T2.tmpl", `{{define "T2"}}This is T2{{end}}`},
-	})
-	// Clean up after the test; another quirk of running as an example.
-	defer os.RemoveAll(dir)
-
-	// pattern is the glob pattern used to find all the template files.
-	pattern := filepath.Join(dir, "*.tmpl")
-
-	// Here starts the example proper.
-	// Load the helpers.
-	templates := template.Must(template.ParseGlob(pattern))
-	// Add one driver template to the bunch; we do this with an explicit template definition.
-	_, err := templates.Parse("{{define `driver1`}}Driver 1 calls T1: ({{template `T1`}})\n{{end}}")
-	if err != nil {
-		log.Fatal("parsing driver1: ", err)
-	}
-	// Add another driver template.
-	_, err = templates.Parse("{{define `driver2`}}Driver 2 calls T2: ({{template `T2`}})\n{{end}}")
-	if err != nil {
-		log.Fatal("parsing driver2: ", err)
-	}
-	// We load all the templates before execution. This package does not require
-	// that behavior but html/template's escaping does, so it's a good habit.
-	err = templates.ExecuteTemplate(os.Stdout, "driver1", nil)
-	if err != nil {
-		log.Fatalf("driver1 execution: %s", err)
-	}
-	err = templates.ExecuteTemplate(os.Stdout, "driver2", nil)
-	if err != nil {
-		log.Fatalf("driver2 execution: %s", err)
-	}
-	// Output:
-	// Driver 1 calls T1: (T1 invokes T2: (This is T2))
-	// Driver 2 calls T2: (This is T2)
-}
-
-// The following example is duplicated in text/template; keep them in sync.
-
-// This example demonstrates how to use one group of driver
-// templates with distinct sets of helper templates.
-func ExampleTemplate_share() {
-	// Here we create a temporary directory and populate it with our sample
-	// template definition files; usually the template files would already
-	// exist in some location known to the program.
-	dir := createTestDir([]templateFile{
-		// T0.tmpl is a plain template file that just invokes T1.
-		{"T0.tmpl", "T0 ({{.}} version) invokes T1: ({{template `T1`}})\n"},
-		// T1.tmpl defines a template, T1 that invokes T2. Note T2 is not defined
-		{"T1.tmpl", `{{define "T1"}}T1 invokes T2: ({{template "T2"}}){{end}}`},
-	})
-	// Clean up after the test; another quirk of running as an example.
-	defer os.RemoveAll(dir)
-
-	// pattern is the glob pattern used to find all the template files.
-	pattern := filepath.Join(dir, "*.tmpl")
-
-	// Here starts the example proper.
-	// Load the drivers.
-	drivers := template.Must(template.ParseGlob(pattern))
-
-	// We must define an implementation of the T2 template. First we clone
-	// the drivers, then add a definition of T2 to the template name space.
-
-	// 1. Clone the helper set to create a new name space from which to run them.
-	first, err := drivers.Clone()
-	if err != nil {
-		log.Fatal("cloning helpers: ", err)
-	}
-	// 2. Define T2, version A, and parse it.
-	_, err = first.Parse("{{define `T2`}}T2, version A{{end}}")
-	if err != nil {
-		log.Fatal("parsing T2: ", err)
-	}
-
-	// Now repeat the whole thing, using a different version of T2.
-	// 1. Clone the drivers.
-	second, err := drivers.Clone()
-	if err != nil {
-		log.Fatal("cloning drivers: ", err)
-	}
-	// 2. Define T2, version B, and parse it.
-	_, err = second.Parse("{{define `T2`}}T2, version B{{end}}")
-	if err != nil {
-		log.Fatal("parsing T2: ", err)
-	}
-
-	// Execute the templates in the reverse order to verify the
-	// first is unaffected by the second.
-	err = second.ExecuteTemplate(os.Stdout, "T0.tmpl", "second")
-	if err != nil {
-		log.Fatalf("second execution: %s", err)
-	}
-	err = first.ExecuteTemplate(os.Stdout, "T0.tmpl", "first")
-	if err != nil {
-		log.Fatalf("first: execution: %s", err)
-	}
-
-	// Output:
-	// T0 (second version) invokes T1: (T1 invokes T2: (T2, version B))
-	// T0 (first version) invokes T1: (T1 invokes T2: (T2, version A))
-}
diff --git a/go.dev/cmd/internal/html/template/exec_test.go b/go.dev/cmd/internal/html/template/exec_test.go
deleted file mode 100644
index 6bd824c..0000000
--- a/go.dev/cmd/internal/html/template/exec_test.go
+++ /dev/null
@@ -1,1834 +0,0 @@
-// Copyright 2011 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.
-
-// Tests for template execution, copied from text/template.
-
-package template
-
-import (
-	"bytes"
-	"errors"
-	"flag"
-	"fmt"
-	"io/ioutil"
-	"reflect"
-	"strings"
-	"sync"
-	"testing"
-
-	"golang.org/x/website/go.dev/cmd/internal/text/template"
-)
-
-var debug = flag.Bool("debug", false, "show the errors produced by the tests")
-
-// T has lots of interesting pieces to use to test execution.
-type T struct {
-	// Basics
-	True        bool
-	I           int
-	U16         uint16
-	X, S        string
-	FloatZero   float64
-	ComplexZero complex128
-	// Nested structs.
-	U *U
-	// Struct with String method.
-	V0     V
-	V1, V2 *V
-	// Struct with Error method.
-	W0     W
-	W1, W2 *W
-	// Slices
-	SI      []int
-	SICap   []int
-	SIEmpty []int
-	SB      []bool
-	// Arrays
-	AI [3]int
-	// Maps
-	MSI      map[string]int
-	MSIone   map[string]int // one element, for deterministic output
-	MSIEmpty map[string]int
-	MXI      map[interface{}]int
-	MII      map[int]int
-	MI32S    map[int32]string
-	MI64S    map[int64]string
-	MUI32S   map[uint32]string
-	MUI64S   map[uint64]string
-	MI8S     map[int8]string
-	MUI8S    map[uint8]string
-	SMSI     []map[string]int
-	// Empty interfaces; used to see if we can dig inside one.
-	Empty0 interface{} // nil
-	Empty1 interface{}
-	Empty2 interface{}
-	Empty3 interface{}
-	Empty4 interface{}
-	// Non-empty interfaces.
-	NonEmptyInterface         I
-	NonEmptyInterfacePtS      *I
-	NonEmptyInterfaceNil      I
-	NonEmptyInterfaceTypedNil I
-	// Stringer.
-	Str fmt.Stringer
-	Err error
-	// Pointers
-	PI  *int
-	PS  *string
-	PSI *[]int
-	NIL *int
-	// Function (not method)
-	BinaryFunc      func(string, string) string
-	VariadicFunc    func(...string) string
-	VariadicFuncInt func(int, ...string) string
-	NilOKFunc       func(*int) bool
-	ErrFunc         func() (string, error)
-	PanicFunc       func() string
-	// Template to test evaluation of templates.
-	Tmpl *Template
-	// Unexported field; cannot be accessed by template.
-	unexported int
-}
-
-type S []string
-
-func (S) Method0() string {
-	return "M0"
-}
-
-type U struct {
-	V string
-}
-
-type V struct {
-	j int
-}
-
-func (v *V) String() string {
-	if v == nil {
-		return "nilV"
-	}
-	return fmt.Sprintf("<%d>", v.j)
-}
-
-type W struct {
-	k int
-}
-
-func (w *W) Error() string {
-	if w == nil {
-		return "nilW"
-	}
-	return fmt.Sprintf("[%d]", w.k)
-}
-
-var siVal = I(S{"a", "b"})
-
-var tVal = &T{
-	True:   true,
-	I:      17,
-	U16:    16,
-	X:      "x",
-	S:      "xyz",
-	U:      &U{"v"},
-	V0:     V{6666},
-	V1:     &V{7777}, // leave V2 as nil
-	W0:     W{888},
-	W1:     &W{999}, // leave W2 as nil
-	SI:     []int{3, 4, 5},
-	SICap:  make([]int, 5, 10),
-	AI:     [3]int{3, 4, 5},
-	SB:     []bool{true, false},
-	MSI:    map[string]int{"one": 1, "two": 2, "three": 3},
-	MSIone: map[string]int{"one": 1},
-	MXI:    map[interface{}]int{"one": 1},
-	MII:    map[int]int{1: 1},
-	MI32S:  map[int32]string{1: "one", 2: "two"},
-	MI64S:  map[int64]string{2: "i642", 3: "i643"},
-	MUI32S: map[uint32]string{2: "u322", 3: "u323"},
-	MUI64S: map[uint64]string{2: "ui642", 3: "ui643"},
-	MI8S:   map[int8]string{2: "i82", 3: "i83"},
-	MUI8S:  map[uint8]string{2: "u82", 3: "u83"},
-	SMSI: []map[string]int{
-		{"one": 1, "two": 2},
-		{"eleven": 11, "twelve": 12},
-	},
-	Empty1:                    3,
-	Empty2:                    "empty2",
-	Empty3:                    []int{7, 8},
-	Empty4:                    &U{"UinEmpty"},
-	NonEmptyInterface:         &T{X: "x"},
-	NonEmptyInterfacePtS:      &siVal,
-	NonEmptyInterfaceTypedNil: (*T)(nil),
-	Str:                       bytes.NewBuffer([]byte("foozle")),
-	Err:                       errors.New("erroozle"),
-	PI:                        newInt(23),
-	PS:                        newString("a string"),
-	PSI:                       newIntSlice(21, 22, 23),
-	BinaryFunc:                func(a, b string) string { return fmt.Sprintf("[%s=%s]", a, b) },
-	VariadicFunc:              func(s ...string) string { return fmt.Sprint("<", strings.Join(s, "+"), ">") },
-	VariadicFuncInt:           func(a int, s ...string) string { return fmt.Sprint(a, "=<", strings.Join(s, "+"), ">") },
-	NilOKFunc:                 func(s *int) bool { return s == nil },
-	ErrFunc:                   func() (string, error) { return "bla", nil },
-	PanicFunc:                 func() string { panic("test panic") },
-	Tmpl:                      Must(New("x").Parse("test template")), // "x" is the value of .X
-}
-
-var tSliceOfNil = []*T{nil}
-
-// A non-empty interface.
-type I interface {
-	Method0() string
-}
-
-var iVal I = tVal
-
-// Helpers for creation.
-func newInt(n int) *int {
-	return &n
-}
-
-func newString(s string) *string {
-	return &s
-}
-
-func newIntSlice(n ...int) *[]int {
-	p := new([]int)
-	*p = make([]int, len(n))
-	copy(*p, n)
-	return p
-}
-
-// Simple methods with and without arguments.
-func (t *T) Method0() string {
-	return "M0"
-}
-
-func (t *T) Method1(a int) int {
-	return a
-}
-
-func (t *T) Method2(a uint16, b string) string {
-	return fmt.Sprintf("Method2: %d %s", a, b)
-}
-
-func (t *T) Method3(v interface{}) string {
-	return fmt.Sprintf("Method3: %v", v)
-}
-
-func (t *T) Copy() *T {
-	n := new(T)
-	*n = *t
-	return n
-}
-
-func (t *T) MAdd(a int, b []int) []int {
-	v := make([]int, len(b))
-	for i, x := range b {
-		v[i] = x + a
-	}
-	return v
-}
-
-var myError = errors.New("my error")
-
-// MyError returns a value and an error according to its argument.
-func (t *T) MyError(error bool) (bool, error) {
-	if error {
-		return true, myError
-	}
-	return false, nil
-}
-
-// A few methods to test chaining.
-func (t *T) GetU() *U {
-	return t.U
-}
-
-func (u *U) TrueFalse(b bool) string {
-	if b {
-		return "true"
-	}
-	return ""
-}
-
-func typeOf(arg interface{}) string {
-	return fmt.Sprintf("%T", arg)
-}
-
-type execTest struct {
-	name   string
-	input  string
-	output string
-	data   interface{}
-	ok     bool
-}
-
-// bigInt and bigUint are hex string representing numbers either side
-// of the max int boundary.
-// We do it this way so the test doesn't depend on ints being 32 bits.
-var (
-	bigInt  = fmt.Sprintf("0x%x", int(1<<uint(reflect.TypeOf(0).Bits()-1)-1))
-	bigUint = fmt.Sprintf("0x%x", uint(1<<uint(reflect.TypeOf(0).Bits()-1)))
-)
-
-var execTests = []execTest{
-	// Trivial cases.
-	{"empty", "", "", nil, true},
-	{"text", "some text", "some text", nil, true},
-	{"nil action", "{{nil}}", "", nil, false},
-
-	// Ideal constants.
-	{"ideal int", "{{typeOf 3}}", "int", 0, true},
-	{"ideal float", "{{typeOf 1.0}}", "float64", 0, true},
-	{"ideal exp float", "{{typeOf 1e1}}", "float64", 0, true},
-	{"ideal complex", "{{typeOf 1i}}", "complex128", 0, true},
-	{"ideal int", "{{typeOf " + bigInt + "}}", "int", 0, true},
-	{"ideal too big", "{{typeOf " + bigUint + "}}", "", 0, false},
-	{"ideal nil without type", "{{nil}}", "", 0, false},
-
-	// Fields of structs.
-	{".X", "-{{.X}}-", "-x-", tVal, true},
-	{".U.V", "-{{.U.V}}-", "-v-", tVal, true},
-	{".unexported", "{{.unexported}}", "", tVal, false},
-
-	// Fields on maps.
-	{"map .one", "{{.MSI.one}}", "1", tVal, true},
-	{"map .two", "{{.MSI.two}}", "2", tVal, true},
-	{"map .NO", "{{.MSI.NO}}", "", tVal, true}, // NOTE: <no value> in text/template
-	{"map .one interface", "{{.MXI.one}}", "1", tVal, true},
-	{"map .WRONG args", "{{.MSI.one 1}}", "", tVal, false},
-	{"map .WRONG type", "{{.MII.one}}", "", tVal, false},
-
-	// Dots of all kinds to test basic evaluation.
-	{"dot int", "<{{.}}>", "&lt;13>", 13, true},
-	{"dot uint", "<{{.}}>", "&lt;14>", uint(14), true},
-	{"dot float", "<{{.}}>", "&lt;15.1>", 15.1, true},
-	{"dot bool", "<{{.}}>", "&lt;true>", true, true},
-	{"dot complex", "<{{.}}>", "&lt;(16.2-17i)>", 16.2 - 17i, true},
-	{"dot string", "<{{.}}>", "&lt;hello>", "hello", true},
-	{"dot slice", "<{{.}}>", "&lt;[-1 -2 -3]>", []int{-1, -2, -3}, true},
-	{"dot map", "<{{.}}>", "&lt;map[two:22]>", map[string]int{"two": 22}, true},
-	{"dot struct", "<{{.}}>", "&lt;{7 seven}>", struct {
-		a int
-		b string
-	}{7, "seven"}, true},
-
-	// Variables.
-	{"$ int", "{{$}}", "123", 123, true},
-	{"$.I", "{{$.I}}", "17", tVal, true},
-	{"$.U.V", "{{$.U.V}}", "v", tVal, true},
-	{"declare in action", "{{$x := $.U.V}}{{$x}}", "v", tVal, true},
-	{"simple assignment", "{{$x := 2}}{{$x = 3}}{{$x}}", "3", tVal, true},
-	{"nested assignment",
-		"{{$x := 2}}{{if true}}{{$x = 3}}{{end}}{{$x}}",
-		"3", tVal, true},
-	{"nested assignment changes the last declaration",
-		"{{$x := 1}}{{if true}}{{$x := 2}}{{if true}}{{$x = 3}}{{end}}{{end}}{{$x}}",
-		"1", tVal, true},
-
-	// Type with String method.
-	{"V{6666}.String()", "-{{.V0}}-", "-{6666}-", tVal, true}, //  NOTE: -<6666>- in text/template
-	{"&V{7777}.String()", "-{{.V1}}-", "-&lt;7777&gt;-", tVal, true},
-	{"(*V)(nil).String()", "-{{.V2}}-", "-nilV-", tVal, true},
-
-	// Type with Error method.
-	{"W{888}.Error()", "-{{.W0}}-", "-{888}-", tVal, true}, // NOTE: -[888] in text/template
-	{"&W{999}.Error()", "-{{.W1}}-", "-[999]-", tVal, true},
-	{"(*W)(nil).Error()", "-{{.W2}}-", "-nilW-", tVal, true},
-
-	// Pointers.
-	{"*int", "{{.PI}}", "23", tVal, true},
-	{"*string", "{{.PS}}", "a string", tVal, true},
-	{"*[]int", "{{.PSI}}", "[21 22 23]", tVal, true},
-	{"*[]int[1]", "{{index .PSI 1}}", "22", tVal, true},
-	{"NIL", "{{.NIL}}", "&lt;nil&gt;", tVal, true},
-
-	// Empty interfaces holding values.
-	{"empty nil", "{{.Empty0}}", "", tVal, true}, // NOTE: <no value> in text/template
-	{"empty with int", "{{.Empty1}}", "3", tVal, true},
-	{"empty with string", "{{.Empty2}}", "empty2", tVal, true},
-	{"empty with slice", "{{.Empty3}}", "[7 8]", tVal, true},
-	{"empty with struct", "{{.Empty4}}", "{UinEmpty}", tVal, true},
-	{"empty with struct, field", "{{.Empty4.V}}", "UinEmpty", tVal, true},
-
-	// Edge cases with <no value> with an interface value
-	{"field on interface", "{{.foo}}", "", nil, true},                  // NOTE: <no value> in text/template
-	{"field on parenthesized interface", "{{(.).foo}}", "", nil, true}, // NOTE: <no value> in text/template
-
-	// Issue 31810: Parenthesized first element of pipeline with arguments.
-	// See also TestIssue31810.
-	{"unparenthesized non-function", "{{1 2}}", "", nil, false},
-	{"parenthesized non-function", "{{(1) 2}}", "", nil, false},
-	{"parenthesized non-function with no args", "{{(1)}}", "1", nil, true}, // This is fine.
-
-	// Method calls.
-	{".Method0", "-{{.Method0}}-", "-M0-", tVal, true},
-	{".Method1(1234)", "-{{.Method1 1234}}-", "-1234-", tVal, true},
-	{".Method1(.I)", "-{{.Method1 .I}}-", "-17-", tVal, true},
-	{".Method2(3, .X)", "-{{.Method2 3 .X}}-", "-Method2: 3 x-", tVal, true},
-	{".Method2(.U16, `str`)", "-{{.Method2 .U16 `str`}}-", "-Method2: 16 str-", tVal, true},
-	{".Method2(.U16, $x)", "{{if $x := .X}}-{{.Method2 .U16 $x}}{{end}}-", "-Method2: 16 x-", tVal, true},
-	{".Method3(nil constant)", "-{{.Method3 nil}}-", "-Method3: &lt;nil&gt;-", tVal, true},
-	{".Method3(nil value)", "-{{.Method3 .MXI.unset}}-", "-Method3: &lt;nil&gt;-", tVal, true},
-	{"method on var", "{{if $x := .}}-{{$x.Method2 .U16 $x.X}}{{end}}-", "-Method2: 16 x-", tVal, true},
-	{"method on chained var",
-		"{{range .MSIone}}{{if $.U.TrueFalse $.True}}{{$.U.TrueFalse $.True}}{{else}}WRONG{{end}}{{end}}",
-		"true", tVal, true},
-	{"chained method",
-		"{{range .MSIone}}{{if $.GetU.TrueFalse $.True}}{{$.U.TrueFalse $.True}}{{else}}WRONG{{end}}{{end}}",
-		"true", tVal, true},
-	{"chained method on variable",
-		"{{with $x := .}}{{with .SI}}{{$.GetU.TrueFalse $.True}}{{end}}{{end}}",
-		"true", tVal, true},
-	{".NilOKFunc not nil", "{{call .NilOKFunc .PI}}", "false", tVal, true},
-	{".NilOKFunc nil", "{{call .NilOKFunc nil}}", "true", tVal, true},
-	{"method on nil value from slice", "-{{range .}}{{.Method1 1234}}{{end}}-", "-1234-", tSliceOfNil, true},
-	{"method on typed nil interface value", "{{.NonEmptyInterfaceTypedNil.Method0}}", "M0", tVal, true},
-
-	// Function call builtin.
-	{".BinaryFunc", "{{call .BinaryFunc `1` `2`}}", "[1=2]", tVal, true},
-	{".VariadicFunc0", "{{call .VariadicFunc}}", "&lt;&gt;", tVal, true},
-	{".VariadicFunc2", "{{call .VariadicFunc `he` `llo`}}", "&lt;he&#43;llo&gt;", tVal, true},
-	{".VariadicFuncInt", "{{call .VariadicFuncInt 33 `he` `llo`}}", "33=&lt;he&#43;llo&gt;", tVal, true},
-	{"if .BinaryFunc call", "{{ if .BinaryFunc}}{{call .BinaryFunc `1` `2`}}{{end}}", "[1=2]", tVal, true},
-	{"if not .BinaryFunc call", "{{ if not .BinaryFunc}}{{call .BinaryFunc `1` `2`}}{{else}}No{{end}}", "No", tVal, true},
-	{"Interface Call", `{{stringer .S}}`, "foozle", map[string]interface{}{"S": bytes.NewBufferString("foozle")}, true},
-	{".ErrFunc", "{{call .ErrFunc}}", "bla", tVal, true},
-	{"call nil", "{{call nil}}", "", tVal, false},
-
-	// Erroneous function calls (check args).
-	{".BinaryFuncTooFew", "{{call .BinaryFunc `1`}}", "", tVal, false},
-	{".BinaryFuncTooMany", "{{call .BinaryFunc `1` `2` `3`}}", "", tVal, false},
-	{".BinaryFuncBad0", "{{call .BinaryFunc 1 3}}", "", tVal, false},
-	{".BinaryFuncBad1", "{{call .BinaryFunc `1` 3}}", "", tVal, false},
-	{".VariadicFuncBad0", "{{call .VariadicFunc 3}}", "", tVal, false},
-	{".VariadicFuncIntBad0", "{{call .VariadicFuncInt}}", "", tVal, false},
-	{".VariadicFuncIntBad`", "{{call .VariadicFuncInt `x`}}", "", tVal, false},
-	{".VariadicFuncNilBad", "{{call .VariadicFunc nil}}", "", tVal, false},
-
-	// Pipelines.
-	{"pipeline", "-{{.Method0 | .Method2 .U16}}-", "-Method2: 16 M0-", tVal, true},
-	{"pipeline func", "-{{call .VariadicFunc `llo` | call .VariadicFunc `he` }}-", "-&lt;he&#43;&lt;llo&gt;&gt;-", tVal, true},
-
-	// Nil values aren't missing arguments.
-	{"nil pipeline", "{{ .Empty0 | call .NilOKFunc }}", "true", tVal, true},
-	{"nil call arg", "{{ call .NilOKFunc .Empty0 }}", "true", tVal, true},
-	{"bad nil pipeline", "{{ .Empty0 | .VariadicFunc }}", "", tVal, false},
-
-	// Parenthesized expressions
-	{"parens in pipeline", "{{printf `%d %d %d` (1) (2 | add 3) (add 4 (add 5 6))}}", "1 5 15", tVal, true},
-
-	// Parenthesized expressions with field accesses
-	{"parens: $ in paren", "{{($).X}}", "x", tVal, true},
-	{"parens: $.GetU in paren", "{{($.GetU).V}}", "v", tVal, true},
-	{"parens: $ in paren in pipe", "{{($ | echo).X}}", "x", tVal, true},
-	{"parens: spaces and args", `{{(makemap "up" "down" "left" "right").left}}`, "right", tVal, true},
-
-	// If.
-	{"if true", "{{if true}}TRUE{{end}}", "TRUE", tVal, true},
-	{"if false", "{{if false}}TRUE{{else}}FALSE{{end}}", "FALSE", tVal, true},
-	{"if nil", "{{if nil}}TRUE{{end}}", "", tVal, false},
-	{"if on typed nil interface value", "{{if .NonEmptyInterfaceTypedNil}}TRUE{{ end }}", "", tVal, true},
-	{"if 1", "{{if 1}}NON-ZERO{{else}}ZERO{{end}}", "NON-ZERO", tVal, true},
-	{"if 0", "{{if 0}}NON-ZERO{{else}}ZERO{{end}}", "ZERO", tVal, true},
-	{"if 1.5", "{{if 1.5}}NON-ZERO{{else}}ZERO{{end}}", "NON-ZERO", tVal, true},
-	{"if 0.0", "{{if .FloatZero}}NON-ZERO{{else}}ZERO{{end}}", "ZERO", tVal, true},
-	{"if 1.5i", "{{if 1.5i}}NON-ZERO{{else}}ZERO{{end}}", "NON-ZERO", tVal, true},
-	{"if 0.0i", "{{if .ComplexZero}}NON-ZERO{{else}}ZERO{{end}}", "ZERO", tVal, true},
-	{"if emptystring", "{{if ``}}NON-EMPTY{{else}}EMPTY{{end}}", "EMPTY", tVal, true},
-	{"if string", "{{if `notempty`}}NON-EMPTY{{else}}EMPTY{{end}}", "NON-EMPTY", tVal, true},
-	{"if emptyslice", "{{if .SIEmpty}}NON-EMPTY{{else}}EMPTY{{end}}", "EMPTY", tVal, true},
-	{"if slice", "{{if .SI}}NON-EMPTY{{else}}EMPTY{{end}}", "NON-EMPTY", tVal, true},
-	{"if emptymap", "{{if .MSIEmpty}}NON-EMPTY{{else}}EMPTY{{end}}", "EMPTY", tVal, true},
-	{"if map", "{{if .MSI}}NON-EMPTY{{else}}EMPTY{{end}}", "NON-EMPTY", tVal, true},
-	{"if map unset", "{{if .MXI.none}}NON-ZERO{{else}}ZERO{{end}}", "ZERO", tVal, true},
-	{"if map not unset", "{{if not .MXI.none}}ZERO{{else}}NON-ZERO{{end}}", "ZERO", tVal, true},
-	{"if $x with $y int", "{{if $x := true}}{{with $y := .I}}{{$x}},{{$y}}{{end}}{{end}}", "true,17", tVal, true},
-	{"if $x with $x int", "{{if $x := true}}{{with $x := .I}}{{$x}},{{end}}{{$x}}{{end}}", "17,true", tVal, true},
-	{"if else if", "{{if false}}FALSE{{else if true}}TRUE{{end}}", "TRUE", tVal, true},
-	{"if else chain", "{{if eq 1 3}}1{{else if eq 2 3}}2{{else if eq 3 3}}3{{end}}", "3", tVal, true},
-
-	// Print etc.
-	{"print", `{{print "hello, print"}}`, "hello, print", tVal, true},
-	{"print 123", `{{print 1 2 3}}`, "1 2 3", tVal, true},
-	{"print nil", `{{print nil}}`, "&lt;nil&gt;", tVal, true},
-	{"println", `{{println 1 2 3}}`, "1 2 3\n", tVal, true},
-	{"printf int", `{{printf "%04x" 127}}`, "007f", tVal, true},
-	{"printf float", `{{printf "%g" 3.5}}`, "3.5", tVal, true},
-	{"printf complex", `{{printf "%g" 1+7i}}`, "(1&#43;7i)", tVal, true},
-	{"printf string", `{{printf "%s" "hello"}}`, "hello", tVal, true},
-	{"printf function", `{{printf "%#q" zeroArgs}}`, "`zeroArgs`", tVal, true},
-	{"printf field", `{{printf "%s" .U.V}}`, "v", tVal, true},
-	{"printf method", `{{printf "%s" .Method0}}`, "M0", tVal, true},
-	{"printf dot", `{{with .I}}{{printf "%d" .}}{{end}}`, "17", tVal, true},
-	{"printf var", `{{with $x := .I}}{{printf "%d" $x}}{{end}}`, "17", tVal, true},
-	{"printf lots", `{{printf "%d %s %g %s" 127 "hello" 7-3i .Method0}}`, "127 hello (7-3i) M0", tVal, true},
-
-	// HTML.
-	{"html", `{{html "<script>alert(\"XSS\");</script>"}}`,
-		"&lt;script&gt;alert(&#34;XSS&#34;);&lt;/script&gt;", nil, true},
-	{"html pipeline", `{{printf "<script>alert(\"XSS\");</script>" | html}}`,
-		"&lt;script&gt;alert(&#34;XSS&#34;);&lt;/script&gt;", nil, true},
-	{"html", `{{html .PS}}`, "a string", tVal, true},
-	{"html typed nil", `{{html .NIL}}`, "&lt;nil&gt;", tVal, true},
-	{"html untyped nil", `{{html .Empty0}}`, "&lt;nil&gt;", tVal, true}, // NOTE: "&lt;no value&gt;" in text/template
-
-	// JavaScript.
-	{"js", `{{js .}}`, `It\&#39;d be nice.`, `It'd be nice.`, true},
-
-	// URL query.
-	{"urlquery", `{{"http://www.example.org/"|urlquery}}`, "http%3A%2F%2Fwww.example.org%2F", nil, true},
-
-	// Booleans
-	{"not", "{{not true}} {{not false}}", "false true", nil, true},
-	{"and", "{{and false 0}} {{and 1 0}} {{and 0 true}} {{and 1 1}}", "false 0 0 1", nil, true},
-	{"or", "{{or 0 0}} {{or 1 0}} {{or 0 true}} {{or 1 1}}", "0 1 true 1", nil, true},
-	{"boolean if", "{{if and true 1 `hi`}}TRUE{{else}}FALSE{{end}}", "TRUE", tVal, true},
-	{"boolean if not", "{{if and true 1 `hi` | not}}TRUE{{else}}FALSE{{end}}", "FALSE", nil, true},
-
-	// Indexing.
-	{"slice[0]", "{{index .SI 0}}", "3", tVal, true},
-	{"slice[1]", "{{index .SI 1}}", "4", tVal, true},
-	{"slice[HUGE]", "{{index .SI 10}}", "", tVal, false},
-	{"slice[WRONG]", "{{index .SI `hello`}}", "", tVal, false},
-	{"slice[nil]", "{{index .SI nil}}", "", tVal, false},
-	{"map[one]", "{{index .MSI `one`}}", "1", tVal, true},
-	{"map[two]", "{{index .MSI `two`}}", "2", tVal, true},
-	{"map[NO]", "{{index .MSI `XXX`}}", "0", tVal, true},
-	{"map[nil]", "{{index .MSI nil}}", "", tVal, false},
-	{"map[``]", "{{index .MSI ``}}", "0", tVal, true},
-	{"map[WRONG]", "{{index .MSI 10}}", "", tVal, false},
-	{"double index", "{{index .SMSI 1 `eleven`}}", "11", tVal, true},
-	{"nil[1]", "{{index nil 1}}", "", tVal, false},
-	{"map MI64S", "{{index .MI64S 2}}", "i642", tVal, true},
-	{"map MI32S", "{{index .MI32S 2}}", "two", tVal, true},
-	{"map MUI64S", "{{index .MUI64S 3}}", "ui643", tVal, true},
-	{"map MI8S", "{{index .MI8S 3}}", "i83", tVal, true},
-	{"map MUI8S", "{{index .MUI8S 2}}", "u82", tVal, true},
-	{"index of an interface field", "{{index .Empty3 0}}", "7", tVal, true},
-
-	// Slicing.
-	{"slice[:]", "{{slice .SI}}", "[3 4 5]", tVal, true},
-	{"slice[1:]", "{{slice .SI 1}}", "[4 5]", tVal, true},
-	{"slice[1:2]", "{{slice .SI 1 2}}", "[4]", tVal, true},
-	{"slice[-1:]", "{{slice .SI -1}}", "", tVal, false},
-	{"slice[1:-2]", "{{slice .SI 1 -2}}", "", tVal, false},
-	{"slice[1:2:-1]", "{{slice .SI 1 2 -1}}", "", tVal, false},
-	{"slice[2:1]", "{{slice .SI 2 1}}", "", tVal, false},
-	{"slice[2:2:1]", "{{slice .SI 2 2 1}}", "", tVal, false},
-	{"out of range", "{{slice .SI 4 5}}", "", tVal, false},
-	{"out of range", "{{slice .SI 2 2 5}}", "", tVal, false},
-	{"len(s) < indexes < cap(s)", "{{slice .SICap 6 10}}", "[0 0 0 0]", tVal, true},
-	{"len(s) < indexes < cap(s)", "{{slice .SICap 6 10 10}}", "[0 0 0 0]", tVal, true},
-	{"indexes > cap(s)", "{{slice .SICap 10 11}}", "", tVal, false},
-	{"indexes > cap(s)", "{{slice .SICap 6 10 11}}", "", tVal, false},
-	{"array[:]", "{{slice .AI}}", "[3 4 5]", tVal, true},
-	{"array[1:]", "{{slice .AI 1}}", "[4 5]", tVal, true},
-	{"array[1:2]", "{{slice .AI 1 2}}", "[4]", tVal, true},
-	{"string[:]", "{{slice .S}}", "xyz", tVal, true},
-	{"string[0:1]", "{{slice .S 0 1}}", "x", tVal, true},
-	{"string[1:]", "{{slice .S 1}}", "yz", tVal, true},
-	{"string[1:2]", "{{slice .S 1 2}}", "y", tVal, true},
-	{"out of range", "{{slice .S 1 5}}", "", tVal, false},
-	{"3-index slice of string", "{{slice .S 1 2 2}}", "", tVal, false},
-	{"slice of an interface field", "{{slice .Empty3 0 1}}", "[7]", tVal, true},
-
-	// Len.
-	{"slice", "{{len .SI}}", "3", tVal, true},
-	{"map", "{{len .MSI }}", "3", tVal, true},
-	{"len of int", "{{len 3}}", "", tVal, false},
-	{"len of nothing", "{{len .Empty0}}", "", tVal, false},
-	{"len of an interface field", "{{len .Empty3}}", "2", tVal, true},
-
-	// With.
-	{"with true", "{{with true}}{{.}}{{end}}", "true", tVal, true},
-	{"with false", "{{with false}}{{.}}{{else}}FALSE{{end}}", "FALSE", tVal, true},
-	{"with 1", "{{with 1}}{{.}}{{else}}ZERO{{end}}", "1", tVal, true},
-	{"with 0", "{{with 0}}{{.}}{{else}}ZERO{{end}}", "ZERO", tVal, true},
-	{"with 1.5", "{{with 1.5}}{{.}}{{else}}ZERO{{end}}", "1.5", tVal, true},
-	{"with 0.0", "{{with .FloatZero}}{{.}}{{else}}ZERO{{end}}", "ZERO", tVal, true},
-	{"with 1.5i", "{{with 1.5i}}{{.}}{{else}}ZERO{{end}}", "(0&#43;1.5i)", tVal, true},
-	{"with 0.0i", "{{with .ComplexZero}}{{.}}{{else}}ZERO{{end}}", "ZERO", tVal, true},
-	{"with emptystring", "{{with ``}}{{.}}{{else}}EMPTY{{end}}", "EMPTY", tVal, true},
-	{"with string", "{{with `notempty`}}{{.}}{{else}}EMPTY{{end}}", "notempty", tVal, true},
-	{"with emptyslice", "{{with .SIEmpty}}{{.}}{{else}}EMPTY{{end}}", "EMPTY", tVal, true},
-	{"with slice", "{{with .SI}}{{.}}{{else}}EMPTY{{end}}", "[3 4 5]", tVal, true},
-	{"with emptymap", "{{with .MSIEmpty}}{{.}}{{else}}EMPTY{{end}}", "EMPTY", tVal, true},
-	{"with map", "{{with .MSIone}}{{.}}{{else}}EMPTY{{end}}", "map[one:1]", tVal, true},
-	{"with empty interface, struct field", "{{with .Empty4}}{{.V}}{{end}}", "UinEmpty", tVal, true},
-	{"with $x int", "{{with $x := .I}}{{$x}}{{end}}", "17", tVal, true},
-	{"with $x struct.U.V", "{{with $x := $}}{{$x.U.V}}{{end}}", "v", tVal, true},
-	{"with variable and action", "{{with $x := $}}{{$y := $.U.V}}{{$y}}{{end}}", "v", tVal, true},
-	{"with on typed nil interface value", "{{with .NonEmptyInterfaceTypedNil}}TRUE{{ end }}", "", tVal, true},
-
-	// Range.
-	{"range []int", "{{range .SI}}-{{.}}-{{end}}", "-3--4--5-", tVal, true},
-	{"range empty no else", "{{range .SIEmpty}}-{{.}}-{{end}}", "", tVal, true},
-	{"range []int else", "{{range .SI}}-{{.}}-{{else}}EMPTY{{end}}", "-3--4--5-", tVal, true},
-	{"range empty else", "{{range .SIEmpty}}-{{.}}-{{else}}EMPTY{{end}}", "EMPTY", tVal, true},
-	{"range []int break else", "{{range .SI}}-{{.}}-{{break}}NOTREACHED{{else}}EMPTY{{end}}", "-3-", tVal, true},
-	{"range []int continue else", "{{range .SI}}-{{.}}-{{continue}}NOTREACHED{{else}}EMPTY{{end}}", "-3--4--5-", tVal, true},
-	{"range []bool", "{{range .SB}}-{{.}}-{{end}}", "-true--false-", tVal, true},
-	{"range []int method", "{{range .SI | .MAdd .I}}-{{.}}-{{end}}", "-20--21--22-", tVal, true},
-	{"range map", "{{range .MSI}}-{{.}}-{{end}}", "-1--3--2-", tVal, true},
-	{"range empty map no else", "{{range .MSIEmpty}}-{{.}}-{{end}}", "", tVal, true},
-	{"range map else", "{{range .MSI}}-{{.}}-{{else}}EMPTY{{end}}", "-1--3--2-", tVal, true},
-	{"range empty map else", "{{range .MSIEmpty}}-{{.}}-{{else}}EMPTY{{end}}", "EMPTY", tVal, true},
-	{"range empty interface", "{{range .Empty3}}-{{.}}-{{else}}EMPTY{{end}}", "-7--8-", tVal, true},
-	{"range empty nil", "{{range .Empty0}}-{{.}}-{{end}}", "", tVal, true},
-	{"range $x SI", "{{range $x := .SI}}<{{$x}}>{{end}}", "&lt;3>&lt;4>&lt;5>", tVal, true},
-	{"range $x $y SI", "{{range $x, $y := .SI}}<{{$x}}={{$y}}>{{end}}", "&lt;0=3>&lt;1=4>&lt;2=5>", tVal, true},
-	{"range $x MSIone", "{{range $x := .MSIone}}<{{$x}}>{{end}}", "&lt;1>", tVal, true},
-	{"range $x $y MSIone", "{{range $x, $y := .MSIone}}<{{$x}}={{$y}}>{{end}}", "&lt;one=1>", tVal, true},
-	{"range $x PSI", "{{range $x := .PSI}}<{{$x}}>{{end}}", "&lt;21>&lt;22>&lt;23>", tVal, true},
-	{"declare in range", "{{range $x := .PSI}}<{{$foo:=$x}}{{$x}}>{{end}}", "&lt;21>&lt;22>&lt;23>", tVal, true},
-	{"range count", `{{range $i, $x := count 5}}[{{$i}}]{{$x}}{{end}}`, "[0]a[1]b[2]c[3]d[4]e", tVal, true},
-	{"range nil count", `{{range $i, $x := count 0}}{{else}}empty{{end}}`, "empty", tVal, true},
-
-	// Cute examples.
-	{"or as if true", `{{or .SI "slice is empty"}}`, "[3 4 5]", tVal, true},
-	{"or as if false", `{{or .SIEmpty "slice is empty"}}`, "slice is empty", tVal, true},
-
-	// Error handling.
-	{"error method, error", "{{.MyError true}}", "", tVal, false},
-	{"error method, no error", "{{.MyError false}}", "false", tVal, true},
-
-	// Numbers
-	{"decimal", "{{print 1234}}", "1234", tVal, true},
-	{"decimal _", "{{print 12_34}}", "1234", tVal, true},
-	{"binary", "{{print 0b101}}", "5", tVal, true},
-	{"binary _", "{{print 0b_1_0_1}}", "5", tVal, true},
-	{"BINARY", "{{print 0B101}}", "5", tVal, true},
-	{"octal0", "{{print 0377}}", "255", tVal, true},
-	{"octal", "{{print 0o377}}", "255", tVal, true},
-	{"octal _", "{{print 0o_3_7_7}}", "255", tVal, true},
-	{"OCTAL", "{{print 0O377}}", "255", tVal, true},
-	{"hex", "{{print 0x123}}", "291", tVal, true},
-	{"hex _", "{{print 0x1_23}}", "291", tVal, true},
-	{"HEX", "{{print 0X123ABC}}", "1194684", tVal, true},
-	{"float", "{{print 123.4}}", "123.4", tVal, true},
-	{"float _", "{{print 0_0_1_2_3.4}}", "123.4", tVal, true},
-	{"hex float", "{{print +0x1.ep+2}}", "7.5", tVal, true},
-	{"hex float _", "{{print +0x_1.e_0p+0_2}}", "7.5", tVal, true},
-	{"HEX float", "{{print +0X1.EP+2}}", "7.5", tVal, true},
-	{"print multi", "{{print 1_2_3_4 7.5_00_00_00}}", "1234 7.5", tVal, true},
-	{"print multi2", "{{print 1234 0x0_1.e_0p+02}}", "1234 7.5", tVal, true},
-
-	// Fixed bugs.
-	// Must separate dot and receiver; otherwise args are evaluated with dot set to variable.
-	{"bug0", "{{range .MSIone}}{{if $.Method1 .}}X{{end}}{{end}}", "X", tVal, true},
-	// Do not loop endlessly in indirect for non-empty interfaces.
-	// The bug appears with *interface only; looped forever.
-	{"bug1", "{{.Method0}}", "M0", &iVal, true},
-	// Was taking address of interface field, so method set was empty.
-	{"bug2", "{{$.NonEmptyInterface.Method0}}", "M0", tVal, true},
-	// Struct values were not legal in with - mere oversight.
-	{"bug3", "{{with $}}{{.Method0}}{{end}}", "M0", tVal, true},
-	// Nil interface values in if.
-	{"bug4", "{{if .Empty0}}non-nil{{else}}nil{{end}}", "nil", tVal, true},
-	// Stringer.
-	{"bug5", "{{.Str}}", "foozle", tVal, true},
-	{"bug5a", "{{.Err}}", "erroozle", tVal, true},
-	// Args need to be indirected and dereferenced sometimes.
-	{"bug6a", "{{vfunc .V0 .V1}}", "vfunc", tVal, true},
-	{"bug6b", "{{vfunc .V0 .V0}}", "vfunc", tVal, true},
-	{"bug6c", "{{vfunc .V1 .V0}}", "vfunc", tVal, true},
-	{"bug6d", "{{vfunc .V1 .V1}}", "vfunc", tVal, true},
-	// Legal parse but illegal execution: non-function should have no arguments.
-	{"bug7a", "{{3 2}}", "", tVal, false},
-	{"bug7b", "{{$x := 1}}{{$x 2}}", "", tVal, false},
-	{"bug7c", "{{$x := 1}}{{3 | $x}}", "", tVal, false},
-	// Pipelined arg was not being type-checked.
-	{"bug8a", "{{3|oneArg}}", "", tVal, false},
-	{"bug8b", "{{4|dddArg 3}}", "", tVal, false},
-	// A bug was introduced that broke map lookups for lower-case names.
-	{"bug9", "{{.cause}}", "neglect", map[string]string{"cause": "neglect"}, true},
-	// Field chain starting with function did not work.
-	{"bug10", "{{mapOfThree.three}}-{{(mapOfThree).three}}", "3-3", 0, true},
-	// Dereferencing nil pointer while evaluating function arguments should not panic. Issue 7333.
-	{"bug11", "{{valueString .PS}}", "", T{}, false},
-	// 0xef gave constant type float64. Issue 8622.
-	{"bug12xe", "{{printf `%T` 0xef}}", "int", T{}, true},
-	{"bug12xE", "{{printf `%T` 0xEE}}", "int", T{}, true},
-	{"bug12Xe", "{{printf `%T` 0Xef}}", "int", T{}, true},
-	{"bug12XE", "{{printf `%T` 0XEE}}", "int", T{}, true},
-	// Chained nodes did not work as arguments. Issue 8473.
-	{"bug13", "{{print (.Copy).I}}", "17", tVal, true},
-	// Didn't protect against nil or literal values in field chains.
-	{"bug14a", "{{(nil).True}}", "", tVal, false},
-	{"bug14b", "{{$x := nil}}{{$x.anything}}", "", tVal, false},
-	{"bug14c", `{{$x := (1.0)}}{{$y := ("hello")}}{{$x.anything}}{{$y.true}}`, "", tVal, false},
-	// Didn't call validateType on function results. Issue 10800.
-	{"bug15", "{{valueString returnInt}}", "", tVal, false},
-	// Variadic function corner cases. Issue 10946.
-	{"bug16a", "{{true|printf}}", "", tVal, false},
-	{"bug16b", "{{1|printf}}", "", tVal, false},
-	{"bug16c", "{{1.1|printf}}", "", tVal, false},
-	{"bug16d", "{{'x'|printf}}", "", tVal, false},
-	{"bug16e", "{{0i|printf}}", "", tVal, false},
-	{"bug16f", "{{true|twoArgs \"xxx\"}}", "", tVal, false},
-	{"bug16g", "{{\"aaa\" |twoArgs \"bbb\"}}", "twoArgs=bbbaaa", tVal, true},
-	{"bug16h", "{{1|oneArg}}", "", tVal, false},
-	{"bug16i", "{{\"aaa\"|oneArg}}", "oneArg=aaa", tVal, true},
-	{"bug16j", "{{1+2i|printf \"%v\"}}", "(1&#43;2i)", tVal, true},
-	{"bug16k", "{{\"aaa\"|printf }}", "aaa", tVal, true},
-	{"bug17a", "{{.NonEmptyInterface.X}}", "x", tVal, true},
-	{"bug17b", "-{{.NonEmptyInterface.Method1 1234}}-", "-1234-", tVal, true},
-	{"bug17c", "{{len .NonEmptyInterfacePtS}}", "2", tVal, true},
-	{"bug17d", "{{index .NonEmptyInterfacePtS 0}}", "a", tVal, true},
-	{"bug17e", "{{range .NonEmptyInterfacePtS}}-{{.}}-{{end}}", "-a--b-", tVal, true},
-
-	// More variadic function corner cases. Some runes would get evaluated
-	// as constant floats instead of ints. Issue 34483.
-	{"bug18a", "{{eq . '.'}}", "true", '.', true},
-	{"bug18b", "{{eq . 'e'}}", "true", 'e', true},
-	{"bug18c", "{{eq . 'P'}}", "true", 'P', true},
-}
-
-func zeroArgs() string {
-	return "zeroArgs"
-}
-
-func oneArg(a string) string {
-	return "oneArg=" + a
-}
-
-func twoArgs(a, b string) string {
-	return "twoArgs=" + a + b
-}
-
-func dddArg(a int, b ...string) string {
-	return fmt.Sprintln(a, b)
-}
-
-// count returns a channel that will deliver n sequential 1-letter strings starting at "a"
-func count(n int) chan string {
-	if n == 0 {
-		return nil
-	}
-	c := make(chan string)
-	go func() {
-		for i := 0; i < n; i++ {
-			c <- "abcdefghijklmnop"[i : i+1]
-		}
-		close(c)
-	}()
-	return c
-}
-
-// vfunc takes a *V and a V
-func vfunc(V, *V) string {
-	return "vfunc"
-}
-
-// valueString takes a string, not a pointer.
-func valueString(v string) string {
-	return "value is ignored"
-}
-
-// returnInt returns an int
-func returnInt() int {
-	return 7
-}
-
-func add(args ...int) int {
-	sum := 0
-	for _, x := range args {
-		sum += x
-	}
-	return sum
-}
-
-func echo(arg interface{}) interface{} {
-	return arg
-}
-
-func makemap(arg ...string) map[string]string {
-	if len(arg)%2 != 0 {
-		panic("bad makemap")
-	}
-	m := make(map[string]string)
-	for i := 0; i < len(arg); i += 2 {
-		m[arg[i]] = arg[i+1]
-	}
-	return m
-}
-
-func stringer(s fmt.Stringer) string {
-	return s.String()
-}
-
-func mapOfThree() interface{} {
-	return map[string]int{"three": 3}
-}
-
-func testExecute(execTests []execTest, template *Template, t *testing.T) {
-	b := new(bytes.Buffer)
-	funcs := FuncMap{
-		"add":         add,
-		"count":       count,
-		"dddArg":      dddArg,
-		"echo":        echo,
-		"makemap":     makemap,
-		"mapOfThree":  mapOfThree,
-		"oneArg":      oneArg,
-		"returnInt":   returnInt,
-		"stringer":    stringer,
-		"twoArgs":     twoArgs,
-		"typeOf":      typeOf,
-		"valueString": valueString,
-		"vfunc":       vfunc,
-		"zeroArgs":    zeroArgs,
-	}
-	for _, test := range execTests {
-		var tmpl *Template
-		var err error
-		if template == nil {
-			tmpl, err = New(test.name).Funcs(funcs).Parse(test.input)
-		} else {
-			tmpl, err = template.Clone()
-			if err != nil {
-				t.Errorf("%s: clone error: %s", test.name, err)
-				continue
-			}
-			tmpl, err = tmpl.New(test.name).Funcs(funcs).Parse(test.input)
-		}
-		if err != nil {
-			t.Errorf("%s: parse error: %s", test.name, err)
-			continue
-		}
-		b.Reset()
-		err = tmpl.Execute(b, test.data)
-		switch {
-		case !test.ok && err == nil:
-			t.Errorf("%s: expected error; got none", test.name)
-			continue
-		case test.ok && err != nil:
-			t.Errorf("%s: unexpected execute error: %s", test.name, err)
-			continue
-		case !test.ok && err != nil:
-			// expected error, got one
-			if *debug {
-				fmt.Printf("%s: %s\n\t%s\n", test.name, test.input, err)
-			}
-		}
-		result := b.String()
-		if result != test.output {
-			t.Errorf("%s: expected\n\t%q\ngot\n\t%q", test.name, test.output, result)
-		}
-	}
-}
-
-func TestExecute(t *testing.T) {
-	testExecute(execTests, nil, t)
-}
-
-var delimPairs = []string{
-	"", "", // default
-	"{{", "}}", // same as default
-	"|", "|", // same
-	"(日)", "(本)", // peculiar
-}
-
-func TestDelims(t *testing.T) {
-	const hello = "Hello, world"
-	var value = struct{ Str string }{hello}
-	for i := 0; i < len(delimPairs); i += 2 {
-		text := ".Str"
-		left := delimPairs[i+0]
-		trueLeft := left
-		right := delimPairs[i+1]
-		trueRight := right
-		if left == "" { // default case
-			trueLeft = "{{"
-		}
-		if right == "" { // default case
-			trueRight = "}}"
-		}
-		text = trueLeft + text + trueRight
-		// Now add a comment
-		text += trueLeft + "/*comment*/" + trueRight
-		// Now add  an action containing a string.
-		text += trueLeft + `"` + trueLeft + `"` + trueRight
-		// At this point text looks like `{{.Str}}{{/*comment*/}}{{"{{"}}`.
-		tmpl, err := New("delims").Delims(left, right).Parse(text)
-		if err != nil {
-			t.Fatalf("delim %q text %q parse err %s", left, text, err)
-		}
-		var b = new(bytes.Buffer)
-		err = tmpl.Execute(b, value)
-		if err != nil {
-			t.Fatalf("delim %q exec err %s", left, err)
-		}
-		if b.String() != hello+trueLeft {
-			t.Errorf("expected %q got %q", hello+trueLeft, b.String())
-		}
-	}
-}
-
-// Check that an error from a method flows back to the top.
-func TestExecuteError(t *testing.T) {
-	b := new(bytes.Buffer)
-	tmpl := New("error")
-	_, err := tmpl.Parse("{{.MyError true}}")
-	if err != nil {
-		t.Fatalf("parse error: %s", err)
-	}
-	err = tmpl.Execute(b, tVal)
-	if err == nil {
-		t.Errorf("expected error; got none")
-	} else if !strings.Contains(err.Error(), myError.Error()) {
-		if *debug {
-			fmt.Printf("test execute error: %s\n", err)
-		}
-		t.Errorf("expected myError; got %s", err)
-	}
-}
-
-const execErrorText = `line 1
-line 2
-line 3
-{{template "one" .}}
-{{define "one"}}{{template "two" .}}{{end}}
-{{define "two"}}{{template "three" .}}{{end}}
-{{define "three"}}{{index "hi" $}}{{end}}`
-
-// Check that an error from a nested template contains all the relevant information.
-func TestExecError(t *testing.T) {
-	tmpl, err := New("top").Parse(execErrorText)
-	if err != nil {
-		t.Fatal("parse error:", err)
-	}
-	var b bytes.Buffer
-	err = tmpl.Execute(&b, 5) // 5 is out of range indexing "hi"
-	if err == nil {
-		t.Fatal("expected error")
-	}
-	const want = `template: top:7:20: executing "three" at <index "hi" $>: error calling index: index out of range: 5`
-	got := err.Error()
-	if got != want {
-		t.Errorf("expected\n%q\ngot\n%q", want, got)
-	}
-}
-
-func TestJSEscaping(t *testing.T) {
-	testCases := []struct {
-		in, exp string
-	}{
-		{`a`, `a`},
-		{`'foo`, `\'foo`},
-		{`Go "jump" \`, `Go \"jump\" \\`},
-		{`Yukihiro says "今日は世界"`, `Yukihiro says \"今日は世界\"`},
-		{"unprintable \uFDFF", `unprintable \uFDFF`},
-		{`<html>`, `\u003Chtml\u003E`},
-		{`no = in attributes`, `no \u003D in attributes`},
-		{`&#x27; does not become HTML entity`, `\u0026#x27; does not become HTML entity`},
-	}
-	for _, tc := range testCases {
-		s := JSEscapeString(tc.in)
-		if s != tc.exp {
-			t.Errorf("JS escaping [%s] got [%s] want [%s]", tc.in, s, tc.exp)
-		}
-	}
-}
-
-// A nice example: walk a binary tree.
-
-type Tree struct {
-	Val         int
-	Left, Right *Tree
-}
-
-// Use different delimiters to test Set.Delims.
-// Also test the trimming of leading and trailing spaces.
-const treeTemplate = `
-	(- define "tree" -)
-	[
-		(- .Val -)
-		(- with .Left -)
-			(template "tree" . -)
-		(- end -)
-		(- with .Right -)
-			(- template "tree" . -)
-		(- end -)
-	]
-	(- end -)
-`
-
-func TestTree(t *testing.T) {
-	var tree = &Tree{
-		1,
-		&Tree{
-			2, &Tree{
-				3,
-				&Tree{
-					4, nil, nil,
-				},
-				nil,
-			},
-			&Tree{
-				5,
-				&Tree{
-					6, nil, nil,
-				},
-				nil,
-			},
-		},
-		&Tree{
-			7,
-			&Tree{
-				8,
-				&Tree{
-					9, nil, nil,
-				},
-				nil,
-			},
-			&Tree{
-				10,
-				&Tree{
-					11, nil, nil,
-				},
-				nil,
-			},
-		},
-	}
-	tmpl, err := New("root").Delims("(", ")").Parse(treeTemplate)
-	if err != nil {
-		t.Fatal("parse error:", err)
-	}
-	var b bytes.Buffer
-	const expect = "[1[2[3[4]][5[6]]][7[8[9]][10[11]]]]"
-	// First by looking up the template.
-	err = tmpl.Lookup("tree").Execute(&b, tree)
-	if err != nil {
-		t.Fatal("exec error:", err)
-	}
-	result := b.String()
-	if result != expect {
-		t.Errorf("expected %q got %q", expect, result)
-	}
-	// Then direct to execution.
-	b.Reset()
-	err = tmpl.ExecuteTemplate(&b, "tree", tree)
-	if err != nil {
-		t.Fatal("exec error:", err)
-	}
-	result = b.String()
-	if result != expect {
-		t.Errorf("expected %q got %q", expect, result)
-	}
-}
-
-func TestExecuteOnNewTemplate(t *testing.T) {
-	// This is issue 3872.
-	New("Name").Templates()
-	// This is issue 11379.
-	// new(Template).Templates() // TODO: crashes
-	// new(Template).Parse("") // TODO: crashes
-	// new(Template).New("abc").Parse("") // TODO: crashes
-	// new(Template).Execute(nil, nil)                // TODO: crashes; returns an error (but does not crash)
-	// new(Template).ExecuteTemplate(nil, "XXX", nil) // TODO: crashes; returns an error (but does not crash)
-}
-
-const testTemplates = `{{define "one"}}one{{end}}{{define "two"}}two{{end}}`
-
-func TestMessageForExecuteEmpty(t *testing.T) {
-	// Test a truly empty template.
-	tmpl := New("empty")
-	var b bytes.Buffer
-	err := tmpl.Execute(&b, 0)
-	if err == nil {
-		t.Fatal("expected initial error")
-	}
-	got := err.Error()
-	want := `template: "empty" is an incomplete or empty template` // NOTE: text/template has extra "empty: " in message
-	if got != want {
-		t.Errorf("expected error %s got %s", want, got)
-	}
-
-	// Add a non-empty template to check that the error is helpful.
-	tmpl = New("empty")
-	tests, err := New("").Parse(testTemplates)
-	if err != nil {
-		t.Fatal(err)
-	}
-	tmpl.AddParseTree("secondary", tests.Tree)
-	err = tmpl.Execute(&b, 0)
-	if err == nil {
-		t.Fatal("expected second error")
-	}
-	got = err.Error()
-	if got != want {
-		t.Errorf("expected error %s got %s", want, got)
-	}
-	// Make sure we can execute the secondary.
-	err = tmpl.ExecuteTemplate(&b, "secondary", 0)
-	if err != nil {
-		t.Fatal(err)
-	}
-}
-
-func TestFinalForPrintf(t *testing.T) {
-	tmpl, err := New("").Parse(`{{"x" | printf}}`)
-	if err != nil {
-		t.Fatal(err)
-	}
-	var b bytes.Buffer
-	err = tmpl.Execute(&b, 0)
-	if err != nil {
-		t.Fatal(err)
-	}
-}
-
-type cmpTest struct {
-	expr  string
-	truth string
-	ok    bool
-}
-
-var cmpTests = []cmpTest{
-	{"eq true true", "true", true},
-	{"eq true false", "false", true},
-	{"eq 1+2i 1+2i", "true", true},
-	{"eq 1+2i 1+3i", "false", true},
-	{"eq 1.5 1.5", "true", true},
-	{"eq 1.5 2.5", "false", true},
-	{"eq 1 1", "true", true},
-	{"eq 1 2", "false", true},
-	{"eq `xy` `xy`", "true", true},
-	{"eq `xy` `xyz`", "false", true},
-	{"eq .Uthree .Uthree", "true", true},
-	{"eq .Uthree .Ufour", "false", true},
-	{"eq 3 4 5 6 3", "true", true},
-	{"eq 3 4 5 6 7", "false", true},
-	{"ne true true", "false", true},
-	{"ne true false", "true", true},
-	{"ne 1+2i 1+2i", "false", true},
-	{"ne 1+2i 1+3i", "true", true},
-	{"ne 1.5 1.5", "false", true},
-	{"ne 1.5 2.5", "true", true},
-	{"ne 1 1", "false", true},
-	{"ne 1 2", "true", true},
-	{"ne `xy` `xy`", "false", true},
-	{"ne `xy` `xyz`", "true", true},
-	{"ne .Uthree .Uthree", "false", true},
-	{"ne .Uthree .Ufour", "true", true},
-	{"lt 1.5 1.5", "false", true},
-	{"lt 1.5 2.5", "true", true},
-	{"lt 1 1", "false", true},
-	{"lt 1 2", "true", true},
-	{"lt `xy` `xy`", "false", true},
-	{"lt `xy` `xyz`", "true", true},
-	{"lt .Uthree .Uthree", "false", true},
-	{"lt .Uthree .Ufour", "true", true},
-	{"le 1.5 1.5", "true", true},
-	{"le 1.5 2.5", "true", true},
-	{"le 2.5 1.5", "false", true},
-	{"le 1 1", "true", true},
-	{"le 1 2", "true", true},
-	{"le 2 1", "false", true},
-	{"le `xy` `xy`", "true", true},
-	{"le `xy` `xyz`", "true", true},
-	{"le `xyz` `xy`", "false", true},
-	{"le .Uthree .Uthree", "true", true},
-	{"le .Uthree .Ufour", "true", true},
-	{"le .Ufour .Uthree", "false", true},
-	{"gt 1.5 1.5", "false", true},
-	{"gt 1.5 2.5", "false", true},
-	{"gt 1 1", "false", true},
-	{"gt 2 1", "true", true},
-	{"gt 1 2", "false", true},
-	{"gt `xy` `xy`", "false", true},
-	{"gt `xy` `xyz`", "false", true},
-	{"gt .Uthree .Uthree", "false", true},
-	{"gt .Uthree .Ufour", "false", true},
-	{"gt .Ufour .Uthree", "true", true},
-	{"ge 1.5 1.5", "true", true},
-	{"ge 1.5 2.5", "false", true},
-	{"ge 2.5 1.5", "true", true},
-	{"ge 1 1", "true", true},
-	{"ge 1 2", "false", true},
-	{"ge 2 1", "true", true},
-	{"ge `xy` `xy`", "true", true},
-	{"ge `xy` `xyz`", "false", true},
-	{"ge `xyz` `xy`", "true", true},
-	{"ge .Uthree .Uthree", "true", true},
-	{"ge .Uthree .Ufour", "false", true},
-	{"ge .Ufour .Uthree", "true", true},
-	// Mixing signed and unsigned integers.
-	{"eq .Uthree .Three", "true", true},
-	{"eq .Three .Uthree", "true", true},
-	{"le .Uthree .Three", "true", true},
-	{"le .Three .Uthree", "true", true},
-	{"ge .Uthree .Three", "true", true},
-	{"ge .Three .Uthree", "true", true},
-	{"lt .Uthree .Three", "false", true},
-	{"lt .Three .Uthree", "false", true},
-	{"gt .Uthree .Three", "false", true},
-	{"gt .Three .Uthree", "false", true},
-	{"eq .Ufour .Three", "false", true},
-	{"lt .Ufour .Three", "false", true},
-	{"gt .Ufour .Three", "true", true},
-	{"eq .NegOne .Uthree", "false", true},
-	{"eq .Uthree .NegOne", "false", true},
-	{"ne .NegOne .Uthree", "true", true},
-	{"ne .Uthree .NegOne", "true", true},
-	{"lt .NegOne .Uthree", "true", true},
-	{"lt .Uthree .NegOne", "false", true},
-	{"le .NegOne .Uthree", "true", true},
-	{"le .Uthree .NegOne", "false", true},
-	{"gt .NegOne .Uthree", "false", true},
-	{"gt .Uthree .NegOne", "true", true},
-	{"ge .NegOne .Uthree", "false", true},
-	{"ge .Uthree .NegOne", "true", true},
-	{"eq (index `x` 0) 'x'", "true", true}, // The example that triggered this rule.
-	{"eq (index `x` 0) 'y'", "false", true},
-	{"eq .V1 .V2", "true", true},
-	{"eq .Ptr .Ptr", "true", true},
-	{"eq .Ptr .NilPtr", "false", true},
-	{"eq .NilPtr .NilPtr", "true", true},
-	{"eq .Iface1 .Iface1", "true", true},
-	{"eq .Iface1 .Iface2", "false", true},
-	{"eq .Iface2 .Iface2", "true", true},
-	// Errors
-	{"eq `xy` 1", "", false},       // Different types.
-	{"eq 2 2.0", "", false},        // Different types.
-	{"lt true true", "", false},    // Unordered types.
-	{"lt 1+0i 1+0i", "", false},    // Unordered types.
-	{"eq .Ptr 1", "", false},       // Incompatible types.
-	{"eq .Ptr .NegOne", "", false}, // Incompatible types.
-	{"eq .Map .Map", "", false},    // Uncomparable types.
-	{"eq .Map .V1", "", false},     // Uncomparable types.
-}
-
-func TestComparison(t *testing.T) {
-	b := new(bytes.Buffer)
-	var cmpStruct = struct {
-		Uthree, Ufour  uint
-		NegOne, Three  int
-		Ptr, NilPtr    *int
-		Map            map[int]int
-		V1, V2         V
-		Iface1, Iface2 fmt.Stringer
-	}{
-		Uthree: 3,
-		Ufour:  4,
-		NegOne: -1,
-		Three:  3,
-		Ptr:    new(int),
-		Iface1: b,
-	}
-	for _, test := range cmpTests {
-		text := fmt.Sprintf("{{if %s}}true{{else}}false{{end}}", test.expr)
-		tmpl, err := New("empty").Parse(text)
-		if err != nil {
-			t.Fatalf("%q: %s", test.expr, err)
-		}
-		b.Reset()
-		err = tmpl.Execute(b, &cmpStruct)
-		if test.ok && err != nil {
-			t.Errorf("%s errored incorrectly: %s", test.expr, err)
-			continue
-		}
-		if !test.ok && err == nil {
-			t.Errorf("%s did not error", test.expr)
-			continue
-		}
-		if b.String() != test.truth {
-			t.Errorf("%s: want %s; got %s", test.expr, test.truth, b.String())
-		}
-	}
-}
-
-func TestMissingMapKey(t *testing.T) {
-	data := map[string]int{
-		"x": 99,
-	}
-	tmpl, err := New("t1").Parse("{{.x}} {{.y}}")
-	if err != nil {
-		t.Fatal(err)
-	}
-	var b bytes.Buffer
-	// By default, just get "<no value>" // NOTE: not in html/template, get empty string
-	err = tmpl.Execute(&b, data)
-	if err != nil {
-		t.Fatal(err)
-	}
-	want := "99 "
-	got := b.String()
-	if got != want {
-		t.Errorf("got %q; expected %q", got, want)
-	}
-	// Same if we set the option explicitly to the default.
-	tmpl.Option("missingkey=default")
-	b.Reset()
-	err = tmpl.Execute(&b, data)
-	if err != nil {
-		t.Fatal("default:", err)
-	}
-	got = b.String()
-	if got != want {
-		t.Errorf("got %q; expected %q", got, want)
-	}
-	// Next we ask for a zero value
-	tmpl.Option("missingkey=zero")
-	b.Reset()
-	err = tmpl.Execute(&b, data)
-	if err != nil {
-		t.Fatal("zero:", err)
-	}
-	want = "99 0"
-	got = b.String()
-	if got != want {
-		t.Errorf("got %q; expected %q", got, want)
-	}
-	// Now we ask for an error.
-	tmpl.Option("missingkey=error")
-	err = tmpl.Execute(&b, data)
-	if err == nil {
-		t.Errorf("expected error; got none")
-	}
-	// same Option, but now a nil interface: ask for an error
-	err = tmpl.Execute(&b, nil)
-	t.Log(err)
-	if err == nil {
-		t.Errorf("expected error for nil-interface; got none")
-	}
-}
-
-// Test that the error message for multiline unterminated string
-// refers to the line number of the opening quote.
-func TestUnterminatedStringError(t *testing.T) {
-	_, err := New("X").Parse("hello\n\n{{`unterminated\n\n\n\n}}\n some more\n\n")
-	if err == nil {
-		t.Fatal("expected error")
-	}
-	str := err.Error()
-	if !strings.Contains(str, "X:3: unterminated raw quoted string") {
-		t.Fatalf("unexpected error: %s", str)
-	}
-}
-
-const alwaysErrorText = "always be failing"
-
-var alwaysError = errors.New(alwaysErrorText)
-
-type ErrorWriter int
-
-func (e ErrorWriter) Write(p []byte) (int, error) {
-	return 0, alwaysError
-}
-
-func TestExecuteGivesExecError(t *testing.T) {
-	// First, a non-execution error shouldn't be an ExecError.
-	tmpl, err := New("X").Parse("hello")
-	if err != nil {
-		t.Fatal(err)
-	}
-	err = tmpl.Execute(ErrorWriter(0), 0)
-	if err == nil {
-		t.Fatal("expected error; got none")
-	}
-	if err.Error() != alwaysErrorText {
-		t.Errorf("expected %q error; got %q", alwaysErrorText, err)
-	}
-	// This one should be an ExecError.
-	tmpl, err = New("X").Parse("hello, {{.X.Y}}")
-	if err != nil {
-		t.Fatal(err)
-	}
-	err = tmpl.Execute(ioutil.Discard, 0)
-	if err == nil {
-		t.Fatal("expected error; got none")
-	}
-	eerr, ok := err.(template.ExecError)
-	if !ok {
-		t.Fatalf("did not expect ExecError %s", eerr)
-	}
-	expect := "field X in type int"
-	if !strings.Contains(err.Error(), expect) {
-		t.Errorf("expected %q; got %q", expect, err)
-	}
-}
-
-func funcNameTestFunc() int {
-	return 0
-}
-
-func TestGoodFuncNames(t *testing.T) {
-	names := []string{
-		"_",
-		"a",
-		"a1",
-		"a1",
-		"Ӵ",
-	}
-	for _, name := range names {
-		tmpl := New("X").Funcs(
-			FuncMap{
-				name: funcNameTestFunc,
-			},
-		)
-		if tmpl == nil {
-			t.Fatalf("nil result for %q", name)
-		}
-	}
-}
-
-func TestBadFuncNames(t *testing.T) {
-	names := []string{
-		"",
-		"2",
-		"a-b",
-	}
-	for _, name := range names {
-		testBadFuncName(name, t)
-	}
-}
-
-func testBadFuncName(name string, t *testing.T) {
-	t.Helper()
-	defer func() {
-		recover()
-	}()
-	New("X").Funcs(
-		FuncMap{
-			name: funcNameTestFunc,
-		},
-	)
-	// If we get here, the name did not cause a panic, which is how Funcs
-	// reports an error.
-	t.Errorf("%q succeeded incorrectly as function name", name)
-}
-
-func TestBlock(t *testing.T) {
-	const (
-		input   = `a({{block "inner" .}}bar({{.}})baz{{end}})b`
-		want    = `a(bar(hello)baz)b`
-		overlay = `{{define "inner"}}foo({{.}})bar{{end}}`
-		want2   = `a(foo(goodbye)bar)b`
-	)
-	tmpl, err := New("outer").Parse(input)
-	if err != nil {
-		t.Fatal(err)
-	}
-	tmpl2, err := Must(tmpl.Clone()).Parse(overlay)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	var buf bytes.Buffer
-	if err := tmpl.Execute(&buf, "hello"); err != nil {
-		t.Fatal(err)
-	}
-	if got := buf.String(); got != want {
-		t.Errorf("got %q, want %q", got, want)
-	}
-
-	buf.Reset()
-	if err := tmpl2.Execute(&buf, "goodbye"); err != nil {
-		t.Fatal(err)
-	}
-	if got := buf.String(); got != want2 {
-		t.Errorf("got %q, want %q", got, want2)
-	}
-}
-
-func TestEvalFieldErrors(t *testing.T) {
-	tests := []struct {
-		name, src string
-		value     interface{}
-		want      string
-	}{
-		{
-			// Check that calling an invalid field on nil pointer
-			// prints a field error instead of a distracting nil
-			// pointer error. https://golang.org/issue/15125
-			"MissingFieldOnNil",
-			"{{.MissingField}}",
-			(*T)(nil),
-			"can't evaluate field MissingField in type *template.T",
-		},
-		{
-			"MissingFieldOnNonNil",
-			"{{.MissingField}}",
-			&T{},
-			"can't evaluate field MissingField in type *template.T",
-		},
-		{
-			"ExistingFieldOnNil",
-			"{{.X}}",
-			(*T)(nil),
-			"nil pointer evaluating *template.T.X",
-		},
-		{
-			"MissingKeyOnNilMap",
-			"{{.MissingKey}}",
-			(*map[string]string)(nil),
-			"nil pointer evaluating *map[string]string.MissingKey",
-		},
-		{
-			"MissingKeyOnNilMapPtr",
-			"{{.MissingKey}}",
-			(*map[string]string)(nil),
-			"nil pointer evaluating *map[string]string.MissingKey",
-		},
-		{
-			"MissingKeyOnMapPtrToNil",
-			"{{.MissingKey}}",
-			&map[string]string{},
-			"<nil>",
-		},
-	}
-	for _, tc := range tests {
-		t.Run(tc.name, func(t *testing.T) {
-			tmpl := Must(New("tmpl").Parse(tc.src))
-			err := tmpl.Execute(ioutil.Discard, tc.value)
-			got := "<nil>"
-			if err != nil {
-				got = err.Error()
-			}
-			if !strings.HasSuffix(got, tc.want) {
-				t.Fatalf("got error %q, want %q", got, tc.want)
-			}
-		})
-	}
-}
-
-func TestMaxExecDepth(t *testing.T) {
-	if testing.Short() {
-		t.Skip("skipping in -short mode")
-	}
-	tmpl := Must(New("tmpl").Parse(`{{template "tmpl" .}}`))
-	err := tmpl.Execute(ioutil.Discard, nil)
-	got := "<nil>"
-	if err != nil {
-		got = err.Error()
-	}
-	const want = "exceeded maximum template depth"
-	if !strings.Contains(got, want) {
-		t.Errorf("got error %q; want %q", got, want)
-	}
-}
-
-func TestAddrOfIndex(t *testing.T) {
-	// golang.org/issue/14916.
-	// Before index worked on reflect.Values, the .String could not be
-	// found on the (incorrectly unaddressable) V value,
-	// in contrast to range, which worked fine.
-	// Also testing that passing a reflect.Value to tmpl.Execute works.
-	texts := []string{
-		`{{range .}}{{.String}}{{end}}`,
-		`{{with index . 0}}{{.String}}{{end}}`,
-	}
-	for _, text := range texts {
-		tmpl := Must(New("tmpl").Parse(text))
-		var buf bytes.Buffer
-		err := tmpl.Execute(&buf, reflect.ValueOf([]V{{1}}))
-		if err != nil {
-			t.Fatalf("%s: Execute: %v", text, err)
-		}
-		if buf.String() != "&lt;1&gt;" {
-			t.Fatalf("%s: template output = %q, want %q", text, &buf, "&lt;1&gt;")
-		}
-	}
-}
-
-func TestInterfaceValues(t *testing.T) {
-	// golang.org/issue/17714.
-	// Before index worked on reflect.Values, interface values
-	// were always implicitly promoted to the underlying value,
-	// except that nil interfaces were promoted to the zero reflect.Value.
-	// Eliminating a round trip to interface{} and back to reflect.Value
-	// eliminated this promotion, breaking these cases.
-	tests := []struct {
-		text string
-		out  string
-	}{
-		{`{{index .Nil 1}}`, "ERROR: index of untyped nil"},
-		{`{{index .Slice 2}}`, "2"},
-		{`{{index .Slice .Two}}`, "2"},
-		{`{{call .Nil 1}}`, "ERROR: call of nil"},
-		{`{{call .PlusOne 1}}`, "2"},
-		{`{{call .PlusOne .One}}`, "2"},
-		{`{{and (index .Slice 0) true}}`, "0"},
-		{`{{and .Zero true}}`, "0"},
-		{`{{and (index .Slice 1) false}}`, "false"},
-		{`{{and .One false}}`, "false"},
-		{`{{or (index .Slice 0) false}}`, "false"},
-		{`{{or .Zero false}}`, "false"},
-		{`{{or (index .Slice 1) true}}`, "1"},
-		{`{{or .One true}}`, "1"},
-		{`{{not (index .Slice 0)}}`, "true"},
-		{`{{not .Zero}}`, "true"},
-		{`{{not (index .Slice 1)}}`, "false"},
-		{`{{not .One}}`, "false"},
-		{`{{eq (index .Slice 0) .Zero}}`, "true"},
-		{`{{eq (index .Slice 1) .One}}`, "true"},
-		{`{{ne (index .Slice 0) .Zero}}`, "false"},
-		{`{{ne (index .Slice 1) .One}}`, "false"},
-		{`{{ge (index .Slice 0) .One}}`, "false"},
-		{`{{ge (index .Slice 1) .Zero}}`, "true"},
-		{`{{gt (index .Slice 0) .One}}`, "false"},
-		{`{{gt (index .Slice 1) .Zero}}`, "true"},
-		{`{{le (index .Slice 0) .One}}`, "true"},
-		{`{{le (index .Slice 1) .Zero}}`, "false"},
-		{`{{lt (index .Slice 0) .One}}`, "true"},
-		{`{{lt (index .Slice 1) .Zero}}`, "false"},
-	}
-
-	for _, tt := range tests {
-		tmpl := Must(New("tmpl").Parse(tt.text))
-		var buf bytes.Buffer
-		err := tmpl.Execute(&buf, map[string]interface{}{
-			"PlusOne": func(n int) int {
-				return n + 1
-			},
-			"Slice": []int{0, 1, 2, 3},
-			"One":   1,
-			"Two":   2,
-			"Nil":   nil,
-			"Zero":  0,
-		})
-		if strings.HasPrefix(tt.out, "ERROR:") {
-			e := strings.TrimSpace(strings.TrimPrefix(tt.out, "ERROR:"))
-			if err == nil || !strings.Contains(err.Error(), e) {
-				t.Errorf("%s: Execute: %v, want error %q", tt.text, err, e)
-			}
-			continue
-		}
-		if err != nil {
-			t.Errorf("%s: Execute: %v", tt.text, err)
-			continue
-		}
-		if buf.String() != tt.out {
-			t.Errorf("%s: template output = %q, want %q", tt.text, &buf, tt.out)
-		}
-	}
-}
-
-// Check that panics during calls are recovered and returned as errors.
-func TestExecutePanicDuringCall(t *testing.T) {
-	funcs := map[string]interface{}{
-		"doPanic": func() string {
-			panic("custom panic string")
-		},
-	}
-	tests := []struct {
-		name    string
-		input   string
-		data    interface{}
-		wantErr string
-	}{
-		{
-			"direct func call panics",
-			"{{doPanic}}", (*T)(nil),
-			`template: t:1:2: executing "t" at <doPanic>: error calling doPanic: custom panic string`,
-		},
-		{
-			"indirect func call panics",
-			"{{call doPanic}}", (*T)(nil),
-			`template: t:1:7: executing "t" at <doPanic>: error calling doPanic: custom panic string`,
-		},
-		{
-			"direct method call panics",
-			"{{.GetU}}", (*T)(nil),
-			`template: t:1:2: executing "t" at <.GetU>: error calling GetU: runtime error: invalid memory address or nil pointer dereference`,
-		},
-		{
-			"indirect method call panics",
-			"{{call .GetU}}", (*T)(nil),
-			`template: t:1:7: executing "t" at <.GetU>: error calling GetU: runtime error: invalid memory address or nil pointer dereference`,
-		},
-		{
-			"func field call panics",
-			"{{call .PanicFunc}}", tVal,
-			`template: t:1:2: executing "t" at <call .PanicFunc>: error calling call: test panic`,
-		},
-		{
-			"method call on nil interface",
-			"{{.NonEmptyInterfaceNil.Method0}}", tVal,
-			`template: t:1:23: executing "t" at <.NonEmptyInterfaceNil.Method0>: nil pointer evaluating template.I.Method0`,
-		},
-	}
-	for _, tc := range tests {
-		b := new(bytes.Buffer)
-		tmpl, err := New("t").Funcs(funcs).Parse(tc.input)
-		if err != nil {
-			t.Fatalf("parse error: %s", err)
-		}
-		err = tmpl.Execute(b, tc.data)
-		if err == nil {
-			t.Errorf("%s: expected error; got none", tc.name)
-		} else if !strings.Contains(err.Error(), tc.wantErr) {
-			if *debug {
-				fmt.Printf("%s: test execute error: %s\n", tc.name, err)
-			}
-			t.Errorf("%s: expected error:\n%s\ngot:\n%s", tc.name, tc.wantErr, err)
-		}
-	}
-}
-
-// Issue 31810. Check that a parenthesized first argument behaves properly.
-func TestIssue31810(t *testing.T) {
-	t.Skip("broken in html/template")
-
-	// A simple value with no arguments is fine.
-	var b bytes.Buffer
-	const text = "{{ (.)  }}"
-	tmpl, err := New("").Parse(text)
-	if err != nil {
-		t.Error(err)
-	}
-	err = tmpl.Execute(&b, "result")
-	if err != nil {
-		t.Error(err)
-	}
-	if b.String() != "result" {
-		t.Errorf("%s got %q, expected %q", text, b.String(), "result")
-	}
-
-	// Even a plain function fails - need to use call.
-	f := func() string { return "result" }
-	b.Reset()
-	err = tmpl.Execute(&b, f)
-	if err == nil {
-		t.Error("expected error with no call, got none")
-	}
-
-	// Works if the function is explicitly called.
-	const textCall = "{{ (call .)  }}"
-	tmpl, err = New("").Parse(textCall)
-	b.Reset()
-	err = tmpl.Execute(&b, f)
-	if err != nil {
-		t.Error(err)
-	}
-	if b.String() != "result" {
-		t.Errorf("%s got %q, expected %q", textCall, b.String(), "result")
-	}
-}
-
-// Issue 39807. There was a race applying escapeTemplate.
-
-const raceText = `
-{{- define "jstempl" -}}
-var v = "v";
-{{- end -}}
-<script type="application/javascript">
-{{ template "jstempl" $ }}
-</script>
-`
-
-func TestEscapeRace(t *testing.T) {
-	tmpl := New("")
-	_, err := tmpl.New("templ.html").Parse(raceText)
-	if err != nil {
-		t.Fatal(err)
-	}
-	const count = 20
-	for i := 0; i < count; i++ {
-		_, err := tmpl.New(fmt.Sprintf("x%d.html", i)).Parse(`{{ template "templ.html" .}}`)
-		if err != nil {
-			t.Fatal(err)
-		}
-	}
-
-	var wg sync.WaitGroup
-	for i := 0; i < 10; i++ {
-		wg.Add(1)
-		go func() {
-			defer wg.Done()
-			for j := 0; j < count; j++ {
-				sub := tmpl.Lookup(fmt.Sprintf("x%d.html", j))
-				if err := sub.Execute(ioutil.Discard, nil); err != nil {
-					t.Error(err)
-				}
-			}
-		}()
-	}
-	wg.Wait()
-}
-
-func TestRecursiveExecute(t *testing.T) {
-	tmpl := New("")
-
-	recur := func() (HTML, error) {
-		var sb strings.Builder
-		if err := tmpl.ExecuteTemplate(&sb, "subroutine", nil); err != nil {
-			t.Fatal(err)
-		}
-		return HTML(sb.String()), nil
-	}
-
-	m := FuncMap{
-		"recur": recur,
-	}
-
-	top, err := tmpl.New("x.html").Funcs(m).Parse(`{{recur}}`)
-	if err != nil {
-		t.Fatal(err)
-	}
-	_, err = tmpl.New("subroutine").Parse(`<a href="/x?p={{"'a<b'"}}">`)
-	if err != nil {
-		t.Fatal(err)
-	}
-	if err := top.Execute(ioutil.Discard, nil); err != nil {
-		t.Fatal(err)
-	}
-}
-
-// recursiveInvoker is for TestRecursiveExecuteViaMethod.
-type recursiveInvoker struct {
-	t    *testing.T
-	tmpl *Template
-}
-
-func (r *recursiveInvoker) Recur() (string, error) {
-	var sb strings.Builder
-	if err := r.tmpl.ExecuteTemplate(&sb, "subroutine", nil); err != nil {
-		r.t.Fatal(err)
-	}
-	return sb.String(), nil
-}
-
-func TestRecursiveExecuteViaMethod(t *testing.T) {
-	tmpl := New("")
-	top, err := tmpl.New("x.html").Parse(`{{.Recur}}`)
-	if err != nil {
-		t.Fatal(err)
-	}
-	_, err = tmpl.New("subroutine").Parse(`<a href="/x?p={{"'a<b'"}}">`)
-	if err != nil {
-		t.Fatal(err)
-	}
-	r := &recursiveInvoker{
-		t:    t,
-		tmpl: tmpl,
-	}
-	if err := top.Execute(ioutil.Discard, r); err != nil {
-		t.Fatal(err)
-	}
-}
-
-// Issue 43295.
-func TestTemplateFuncsAfterClone(t *testing.T) {
-	s := `{{ f . }}`
-	want := "test"
-	orig := New("orig").Funcs(map[string]interface{}{
-		"f": func(in string) string {
-			return in
-		},
-	}).New("child")
-
-	overviewTmpl := Must(Must(orig.Clone()).Parse(s))
-	var out strings.Builder
-	if err := overviewTmpl.Execute(&out, want); err != nil {
-		t.Fatal(err)
-	}
-	if got := out.String(); got != want {
-		t.Fatalf("got %q; want %q", got, want)
-	}
-}
diff --git a/go.dev/cmd/internal/html/template/html.go b/go.dev/cmd/internal/html/template/html.go
deleted file mode 100644
index 356b829..0000000
--- a/go.dev/cmd/internal/html/template/html.go
+++ /dev/null
@@ -1,265 +0,0 @@
-// Copyright 2011 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 template
-
-import (
-	"bytes"
-	"fmt"
-	"strings"
-	"unicode/utf8"
-)
-
-// htmlNospaceEscaper escapes for inclusion in unquoted attribute values.
-func htmlNospaceEscaper(args ...interface{}) string {
-	s, t := stringify(args...)
-	if t == contentTypeHTML {
-		return htmlReplacer(stripTags(s), htmlNospaceNormReplacementTable, false)
-	}
-	return htmlReplacer(s, htmlNospaceReplacementTable, false)
-}
-
-// attrEscaper escapes for inclusion in quoted attribute values.
-func attrEscaper(args ...interface{}) string {
-	s, t := stringify(args...)
-	if t == contentTypeHTML {
-		return htmlReplacer(stripTags(s), htmlNormReplacementTable, true)
-	}
-	return htmlReplacer(s, htmlReplacementTable, true)
-}
-
-// rcdataEscaper escapes for inclusion in an RCDATA element body.
-func rcdataEscaper(args ...interface{}) string {
-	s, t := stringify(args...)
-	if t == contentTypeHTML {
-		return htmlReplacer(s, htmlNormReplacementTable, true)
-	}
-	return htmlReplacer(s, htmlReplacementTable, true)
-}
-
-// htmlEscaper escapes for inclusion in HTML text.
-func htmlEscaper(args ...interface{}) string {
-	s, t := stringify(args...)
-	if t == contentTypeHTML {
-		return s
-	}
-	return htmlReplacer(s, htmlReplacementTable, true)
-}
-
-// htmlReplacementTable contains the runes that need to be escaped
-// inside a quoted attribute value or in a text node.
-var htmlReplacementTable = []string{
-	// https://www.w3.org/TR/html5/syntax.html#attribute-value-(unquoted)-state
-	// U+0000 NULL Parse error. Append a U+FFFD REPLACEMENT
-	// CHARACTER character to the current attribute's value.
-	// "
-	// and similarly
-	// https://www.w3.org/TR/html5/syntax.html#before-attribute-value-state
-	0:    "\uFFFD",
-	'"':  "&#34;",
-	'&':  "&amp;",
-	'\'': "&#39;",
-	'+':  "&#43;",
-	'<':  "&lt;",
-	'>':  "&gt;",
-}
-
-// htmlNormReplacementTable is like htmlReplacementTable but without '&' to
-// avoid over-encoding existing entities.
-var htmlNormReplacementTable = []string{
-	0:    "\uFFFD",
-	'"':  "&#34;",
-	'\'': "&#39;",
-	'+':  "&#43;",
-	'<':  "&lt;",
-	'>':  "&gt;",
-}
-
-// htmlNospaceReplacementTable contains the runes that need to be escaped
-// inside an unquoted attribute value.
-// The set of runes escaped is the union of the HTML specials and
-// those determined by running the JS below in browsers:
-// <div id=d></div>
-// <script>(function () {
-// var a = [], d = document.getElementById("d"), i, c, s;
-// for (i = 0; i < 0x10000; ++i) {
-//   c = String.fromCharCode(i);
-//   d.innerHTML = "<span title=" + c + "lt" + c + "></span>"
-//   s = d.getElementsByTagName("SPAN")[0];
-//   if (!s || s.title !== c + "lt" + c) { a.push(i.toString(16)); }
-// }
-// document.write(a.join(", "));
-// })()</script>
-var htmlNospaceReplacementTable = []string{
-	0:    "&#xfffd;",
-	'\t': "&#9;",
-	'\n': "&#10;",
-	'\v': "&#11;",
-	'\f': "&#12;",
-	'\r': "&#13;",
-	' ':  "&#32;",
-	'"':  "&#34;",
-	'&':  "&amp;",
-	'\'': "&#39;",
-	'+':  "&#43;",
-	'<':  "&lt;",
-	'=':  "&#61;",
-	'>':  "&gt;",
-	// A parse error in the attribute value (unquoted) and
-	// before attribute value states.
-	// Treated as a quoting character by IE.
-	'`': "&#96;",
-}
-
-// htmlNospaceNormReplacementTable is like htmlNospaceReplacementTable but
-// without '&' to avoid over-encoding existing entities.
-var htmlNospaceNormReplacementTable = []string{
-	0:    "&#xfffd;",
-	'\t': "&#9;",
-	'\n': "&#10;",
-	'\v': "&#11;",
-	'\f': "&#12;",
-	'\r': "&#13;",
-	' ':  "&#32;",
-	'"':  "&#34;",
-	'\'': "&#39;",
-	'+':  "&#43;",
-	'<':  "&lt;",
-	'=':  "&#61;",
-	'>':  "&gt;",
-	// A parse error in the attribute value (unquoted) and
-	// before attribute value states.
-	// Treated as a quoting character by IE.
-	'`': "&#96;",
-}
-
-// htmlReplacer returns s with runes replaced according to replacementTable
-// and when badRunes is true, certain bad runes are allowed through unescaped.
-func htmlReplacer(s string, replacementTable []string, badRunes bool) string {
-	written, b := 0, new(strings.Builder)
-	r, w := rune(0), 0
-	for i := 0; i < len(s); i += w {
-		// Cannot use 'for range s' because we need to preserve the width
-		// of the runes in the input. If we see a decoding error, the input
-		// width will not be utf8.Runelen(r) and we will overrun the buffer.
-		r, w = utf8.DecodeRuneInString(s[i:])
-		if int(r) < len(replacementTable) {
-			if repl := replacementTable[r]; len(repl) != 0 {
-				if written == 0 {
-					b.Grow(len(s))
-				}
-				b.WriteString(s[written:i])
-				b.WriteString(repl)
-				written = i + w
-			}
-		} else if badRunes {
-			// No-op.
-			// IE does not allow these ranges in unquoted attrs.
-		} else if 0xfdd0 <= r && r <= 0xfdef || 0xfff0 <= r && r <= 0xffff {
-			if written == 0 {
-				b.Grow(len(s))
-			}
-			fmt.Fprintf(b, "%s&#x%x;", s[written:i], r)
-			written = i + w
-		}
-	}
-	if written == 0 {
-		return s
-	}
-	b.WriteString(s[written:])
-	return b.String()
-}
-
-// stripTags takes a snippet of HTML and returns only the text content.
-// For example, `<b>&iexcl;Hi!</b> <script>...</script>` -> `&iexcl;Hi! `.
-func stripTags(html string) string {
-	var b bytes.Buffer
-	s, c, i, allText := []byte(html), context{}, 0, true
-	// Using the transition funcs helps us avoid mangling
-	// `<div title="1>2">` or `I <3 Ponies!`.
-	for i != len(s) {
-		if c.delim == delimNone {
-			st := c.state
-			// Use RCDATA instead of parsing into JS or CSS styles.
-			if c.element != elementNone && !isInTag(st) {
-				st = stateRCDATA
-			}
-			d, nread := transitionFunc[st](c, s[i:])
-			i1 := i + nread
-			if c.state == stateText || c.state == stateRCDATA {
-				// Emit text up to the start of the tag or comment.
-				j := i1
-				if d.state != c.state {
-					for j1 := j - 1; j1 >= i; j1-- {
-						if s[j1] == '<' {
-							j = j1
-							break
-						}
-					}
-				}
-				b.Write(s[i:j])
-			} else {
-				allText = false
-			}
-			c, i = d, i1
-			continue
-		}
-		i1 := i + bytes.IndexAny(s[i:], delimEnds[c.delim])
-		if i1 < i {
-			break
-		}
-		if c.delim != delimSpaceOrTagEnd {
-			// Consume any quote.
-			i1++
-		}
-		c, i = context{state: stateTag, element: c.element}, i1
-	}
-	if allText {
-		return html
-	} else if c.state == stateText || c.state == stateRCDATA {
-		b.Write(s[i:])
-	}
-	return b.String()
-}
-
-// htmlNameFilter accepts valid parts of an HTML attribute or tag name or
-// a known-safe HTML attribute.
-func htmlNameFilter(args ...interface{}) string {
-	s, t := stringify(args...)
-	if t == contentTypeHTMLAttr {
-		return s
-	}
-	if len(s) == 0 {
-		// Avoid violation of structure preservation.
-		// <input checked {{.K}}={{.V}}>.
-		// Without this, if .K is empty then .V is the value of
-		// checked, but otherwise .V is the value of the attribute
-		// named .K.
-		return filterFailsafe
-	}
-	s = strings.ToLower(s)
-	if t := attrType(s); t != contentTypePlain {
-		// TODO: Split attr and element name part filters so we can recognize known attributes.
-		return filterFailsafe
-	}
-	for _, r := range s {
-		switch {
-		case '0' <= r && r <= '9':
-		case 'a' <= r && r <= 'z':
-		default:
-			return filterFailsafe
-		}
-	}
-	return s
-}
-
-// commentEscaper returns the empty string regardless of input.
-// Comment content does not correspond to any parsed structure or
-// human-readable content, so the simplest and most secure policy is to drop
-// content interpolated into comments.
-// This approach is equally valid whether or not static comment content is
-// removed from the template.
-func commentEscaper(args ...interface{}) string {
-	return ""
-}
diff --git a/go.dev/cmd/internal/html/template/html_test.go b/go.dev/cmd/internal/html/template/html_test.go
deleted file mode 100644
index f04ee04..0000000
--- a/go.dev/cmd/internal/html/template/html_test.go
+++ /dev/null
@@ -1,97 +0,0 @@
-// Copyright 2011 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 template
-
-import (
-	"html"
-	"strings"
-	"testing"
-)
-
-func TestHTMLNospaceEscaper(t *testing.T) {
-	input := ("\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f" +
-		"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" +
-		` !"#$%&'()*+,-./` +
-		`0123456789:;<=>?` +
-		`@ABCDEFGHIJKLMNO` +
-		`PQRSTUVWXYZ[\]^_` +
-		"`abcdefghijklmno" +
-		"pqrstuvwxyz{|}~\x7f" +
-		"\u00A0\u0100\u2028\u2029\ufeff\ufdec\U0001D11E" +
-		"erroneous\x960") // keep at the end
-
-	want := ("&#xfffd;\x01\x02\x03\x04\x05\x06\x07" +
-		"\x08&#9;&#10;&#11;&#12;&#13;\x0E\x0F" +
-		"\x10\x11\x12\x13\x14\x15\x16\x17" +
-		"\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" +
-		`&#32;!&#34;#$%&amp;&#39;()*&#43;,-./` +
-		`0123456789:;&lt;&#61;&gt;?` +
-		`@ABCDEFGHIJKLMNO` +
-		`PQRSTUVWXYZ[\]^_` +
-		`&#96;abcdefghijklmno` +
-		`pqrstuvwxyz{|}~` + "\u007f" +
-		"\u00A0\u0100\u2028\u2029\ufeff&#xfdec;\U0001D11E" +
-		"erroneous&#xfffd;0") // keep at the end
-
-	got := htmlNospaceEscaper(input)
-	if got != want {
-		t.Errorf("encode: want\n\t%q\nbut got\n\t%q", want, got)
-	}
-
-	r := strings.NewReplacer("\x00", "\ufffd", "\x96", "\ufffd")
-	got, want = html.UnescapeString(got), r.Replace(input)
-	if want != got {
-		t.Errorf("decode: want\n\t%q\nbut got\n\t%q", want, got)
-	}
-}
-
-func TestStripTags(t *testing.T) {
-	tests := []struct {
-		input, want string
-	}{
-		{"", ""},
-		{"Hello, World!", "Hello, World!"},
-		{"foo&amp;bar", "foo&amp;bar"},
-		{`Hello <a href="www.example.com/">World</a>!`, "Hello World!"},
-		{"Foo <textarea>Bar</textarea> Baz", "Foo Bar Baz"},
-		{"Foo <!-- Bar --> Baz", "Foo  Baz"},
-		{"<", "<"},
-		{"foo < bar", "foo < bar"},
-		{`Foo<script type="text/javascript">alert(1337)</script>Bar`, "FooBar"},
-		{`Foo<div title="1>2">Bar`, "FooBar"},
-		{`I <3 Ponies!`, `I <3 Ponies!`},
-		{`<script>foo()</script>`, ``},
-	}
-
-	for _, test := range tests {
-		if got := stripTags(test.input); got != test.want {
-			t.Errorf("%q: want %q, got %q", test.input, test.want, got)
-		}
-	}
-}
-
-func BenchmarkHTMLNospaceEscaper(b *testing.B) {
-	for i := 0; i < b.N; i++ {
-		htmlNospaceEscaper("The <i>quick</i>,\r\n<span style='color:brown'>brown</span> fox jumps\u2028over the <canine class=\"lazy\">dog</canine>")
-	}
-}
-
-func BenchmarkHTMLNospaceEscaperNoSpecials(b *testing.B) {
-	for i := 0; i < b.N; i++ {
-		htmlNospaceEscaper("The_quick,_brown_fox_jumps_over_the_lazy_dog.")
-	}
-}
-
-func BenchmarkStripTags(b *testing.B) {
-	for i := 0; i < b.N; i++ {
-		stripTags("The <i>quick</i>,\r\n<span style='color:brown'>brown</span> fox jumps\u2028over the <canine class=\"lazy\">dog</canine>")
-	}
-}
-
-func BenchmarkStripTagsNoSpecials(b *testing.B) {
-	for i := 0; i < b.N; i++ {
-		stripTags("The quick, brown fox jumps over the lazy dog.")
-	}
-}
diff --git a/go.dev/cmd/internal/html/template/js.go b/go.dev/cmd/internal/html/template/js.go
deleted file mode 100644
index ea9c183..0000000
--- a/go.dev/cmd/internal/html/template/js.go
+++ /dev/null
@@ -1,431 +0,0 @@
-// Copyright 2011 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 template
-
-import (
-	"bytes"
-	"encoding/json"
-	"fmt"
-	"reflect"
-	"strings"
-	"unicode/utf8"
-)
-
-// nextJSCtx returns the context that determines whether a slash after the
-// given run of tokens starts a regular expression instead of a division
-// operator: / or /=.
-//
-// This assumes that the token run does not include any string tokens, comment
-// tokens, regular expression literal tokens, or division operators.
-//
-// This fails on some valid but nonsensical JavaScript programs like
-// "x = ++/foo/i" which is quite different than "x++/foo/i", but is not known to
-// fail on any known useful programs. It is based on the draft
-// JavaScript 2.0 lexical grammar and requires one token of lookbehind:
-// https://www.mozilla.org/js/language/js20-2000-07/rationale/syntax.html
-func nextJSCtx(s []byte, preceding jsCtx) jsCtx {
-	s = bytes.TrimRight(s, "\t\n\f\r \u2028\u2029")
-	if len(s) == 0 {
-		return preceding
-	}
-
-	// All cases below are in the single-byte UTF-8 group.
-	switch c, n := s[len(s)-1], len(s); c {
-	case '+', '-':
-		// ++ and -- are not regexp preceders, but + and - are whether
-		// they are used as infix or prefix operators.
-		start := n - 1
-		// Count the number of adjacent dashes or pluses.
-		for start > 0 && s[start-1] == c {
-			start--
-		}
-		if (n-start)&1 == 1 {
-			// Reached for trailing minus signs since "---" is the
-			// same as "-- -".
-			return jsCtxRegexp
-		}
-		return jsCtxDivOp
-	case '.':
-		// Handle "42."
-		if n != 1 && '0' <= s[n-2] && s[n-2] <= '9' {
-			return jsCtxDivOp
-		}
-		return jsCtxRegexp
-	// Suffixes for all punctuators from section 7.7 of the language spec
-	// that only end binary operators not handled above.
-	case ',', '<', '>', '=', '*', '%', '&', '|', '^', '?':
-		return jsCtxRegexp
-	// Suffixes for all punctuators from section 7.7 of the language spec
-	// that are prefix operators not handled above.
-	case '!', '~':
-		return jsCtxRegexp
-	// Matches all the punctuators from section 7.7 of the language spec
-	// that are open brackets not handled above.
-	case '(', '[':
-		return jsCtxRegexp
-	// Matches all the punctuators from section 7.7 of the language spec
-	// that precede expression starts.
-	case ':', ';', '{':
-		return jsCtxRegexp
-	// CAVEAT: the close punctuators ('}', ']', ')') precede div ops and
-	// are handled in the default except for '}' which can precede a
-	// division op as in
-	//    ({ valueOf: function () { return 42 } } / 2
-	// which is valid, but, in practice, developers don't divide object
-	// literals, so our heuristic works well for code like
-	//    function () { ... }  /foo/.test(x) && sideEffect();
-	// The ')' punctuator can precede a regular expression as in
-	//     if (b) /foo/.test(x) && ...
-	// but this is much less likely than
-	//     (a + b) / c
-	case '}':
-		return jsCtxRegexp
-	default:
-		// Look for an IdentifierName and see if it is a keyword that
-		// can precede a regular expression.
-		j := n
-		for j > 0 && isJSIdentPart(rune(s[j-1])) {
-			j--
-		}
-		if regexpPrecederKeywords[string(s[j:])] {
-			return jsCtxRegexp
-		}
-	}
-	// Otherwise is a punctuator not listed above, or
-	// a string which precedes a div op, or an identifier
-	// which precedes a div op.
-	return jsCtxDivOp
-}
-
-// regexpPrecederKeywords is a set of reserved JS keywords that can precede a
-// regular expression in JS source.
-var regexpPrecederKeywords = map[string]bool{
-	"break":      true,
-	"case":       true,
-	"continue":   true,
-	"delete":     true,
-	"do":         true,
-	"else":       true,
-	"finally":    true,
-	"in":         true,
-	"instanceof": true,
-	"return":     true,
-	"throw":      true,
-	"try":        true,
-	"typeof":     true,
-	"void":       true,
-}
-
-var jsonMarshalType = reflect.TypeOf((*json.Marshaler)(nil)).Elem()
-
-// indirectToJSONMarshaler returns the value, after dereferencing as many times
-// as necessary to reach the base type (or nil) or an implementation of json.Marshal.
-func indirectToJSONMarshaler(a interface{}) interface{} {
-	// text/template now supports passing untyped nil as a func call
-	// argument, so we must support it. Otherwise we'd panic below, as one
-	// cannot call the Type or Interface methods on an invalid
-	// reflect.Value. See golang.org/issue/18716.
-	if a == nil {
-		return nil
-	}
-
-	v := reflect.ValueOf(a)
-	for !v.Type().Implements(jsonMarshalType) && v.Kind() == reflect.Ptr && !v.IsNil() {
-		v = v.Elem()
-	}
-	return v.Interface()
-}
-
-// jsValEscaper escapes its inputs to a JS Expression (section 11.14) that has
-// neither side-effects nor free variables outside (NaN, Infinity).
-func jsValEscaper(args ...interface{}) string {
-	var a interface{}
-	if len(args) == 1 {
-		a = indirectToJSONMarshaler(args[0])
-		switch t := a.(type) {
-		case JS:
-			return string(t)
-		case JSStr:
-			// TODO: normalize quotes.
-			return `"` + string(t) + `"`
-		case json.Marshaler:
-			// Do not treat as a Stringer.
-		case fmt.Stringer:
-			a = t.String()
-		}
-	} else {
-		for i, arg := range args {
-			args[i] = indirectToJSONMarshaler(arg)
-		}
-		a = fmt.Sprint(args...)
-	}
-	// TODO: detect cycles before calling Marshal which loops infinitely on
-	// cyclic data. This may be an unacceptable DoS risk.
-	b, err := json.Marshal(a)
-	if err != nil {
-		// Put a space before comment so that if it is flush against
-		// a division operator it is not turned into a line comment:
-		//     x/{{y}}
-		// turning into
-		//     x//* error marshaling y:
-		//          second line of error message */null
-		return fmt.Sprintf(" /* %s */null ", strings.ReplaceAll(err.Error(), "*/", "* /"))
-	}
-
-	// TODO: maybe post-process output to prevent it from containing
-	// "<!--", "-->", "<![CDATA[", "]]>", or "</script"
-	// in case custom marshalers produce output containing those.
-	// Note: Do not use \x escaping to save bytes because it is not JSON compatible and this escaper
-	// supports ld+json content-type.
-	if len(b) == 0 {
-		// In, `x=y/{{.}}*z` a json.Marshaler that produces "" should
-		// not cause the output `x=y/*z`.
-		return " null "
-	}
-	first, _ := utf8.DecodeRune(b)
-	last, _ := utf8.DecodeLastRune(b)
-	var buf strings.Builder
-	// Prevent IdentifierNames and NumericLiterals from running into
-	// keywords: in, instanceof, typeof, void
-	pad := isJSIdentPart(first) || isJSIdentPart(last)
-	if pad {
-		buf.WriteByte(' ')
-	}
-	written := 0
-	// Make sure that json.Marshal escapes codepoints U+2028 & U+2029
-	// so it falls within the subset of JSON which is valid JS.
-	for i := 0; i < len(b); {
-		rune, n := utf8.DecodeRune(b[i:])
-		repl := ""
-		if rune == 0x2028 {
-			repl = `\u2028`
-		} else if rune == 0x2029 {
-			repl = `\u2029`
-		}
-		if repl != "" {
-			buf.Write(b[written:i])
-			buf.WriteString(repl)
-			written = i + n
-		}
-		i += n
-	}
-	if buf.Len() != 0 {
-		buf.Write(b[written:])
-		if pad {
-			buf.WriteByte(' ')
-		}
-		return buf.String()
-	}
-	return string(b)
-}
-
-// jsStrEscaper produces a string that can be included between quotes in
-// JavaScript source, in JavaScript embedded in an HTML5 <script> element,
-// or in an HTML5 event handler attribute such as onclick.
-func jsStrEscaper(args ...interface{}) string {
-	s, t := stringify(args...)
-	if t == contentTypeJSStr {
-		return replace(s, jsStrNormReplacementTable)
-	}
-	return replace(s, jsStrReplacementTable)
-}
-
-// jsRegexpEscaper behaves like jsStrEscaper but escapes regular expression
-// specials so the result is treated literally when included in a regular
-// expression literal. /foo{{.X}}bar/ matches the string "foo" followed by
-// the literal text of {{.X}} followed by the string "bar".
-func jsRegexpEscaper(args ...interface{}) string {
-	s, _ := stringify(args...)
-	s = replace(s, jsRegexpReplacementTable)
-	if s == "" {
-		// /{{.X}}/ should not produce a line comment when .X == "".
-		return "(?:)"
-	}
-	return s
-}
-
-// replace replaces each rune r of s with replacementTable[r], provided that
-// r < len(replacementTable). If replacementTable[r] is the empty string then
-// no replacement is made.
-// It also replaces runes U+2028 and U+2029 with the raw strings `\u2028` and
-// `\u2029`.
-func replace(s string, replacementTable []string) string {
-	var b strings.Builder
-	r, w, written := rune(0), 0, 0
-	for i := 0; i < len(s); i += w {
-		// See comment in htmlEscaper.
-		r, w = utf8.DecodeRuneInString(s[i:])
-		var repl string
-		switch {
-		case int(r) < len(lowUnicodeReplacementTable):
-			repl = lowUnicodeReplacementTable[r]
-		case int(r) < len(replacementTable) && replacementTable[r] != "":
-			repl = replacementTable[r]
-		case r == '\u2028':
-			repl = `\u2028`
-		case r == '\u2029':
-			repl = `\u2029`
-		default:
-			continue
-		}
-		if written == 0 {
-			b.Grow(len(s))
-		}
-		b.WriteString(s[written:i])
-		b.WriteString(repl)
-		written = i + w
-	}
-	if written == 0 {
-		return s
-	}
-	b.WriteString(s[written:])
-	return b.String()
-}
-
-var lowUnicodeReplacementTable = []string{
-	0: `\u0000`, 1: `\u0001`, 2: `\u0002`, 3: `\u0003`, 4: `\u0004`, 5: `\u0005`, 6: `\u0006`,
-	'\a': `\u0007`,
-	'\b': `\u0008`,
-	'\t': `\t`,
-	'\n': `\n`,
-	'\v': `\u000b`, // "\v" == "v" on IE 6.
-	'\f': `\f`,
-	'\r': `\r`,
-	0xe:  `\u000e`, 0xf: `\u000f`, 0x10: `\u0010`, 0x11: `\u0011`, 0x12: `\u0012`, 0x13: `\u0013`,
-	0x14: `\u0014`, 0x15: `\u0015`, 0x16: `\u0016`, 0x17: `\u0017`, 0x18: `\u0018`, 0x19: `\u0019`,
-	0x1a: `\u001a`, 0x1b: `\u001b`, 0x1c: `\u001c`, 0x1d: `\u001d`, 0x1e: `\u001e`, 0x1f: `\u001f`,
-}
-
-var jsStrReplacementTable = []string{
-	0:    `\u0000`,
-	'\t': `\t`,
-	'\n': `\n`,
-	'\v': `\u000b`, // "\v" == "v" on IE 6.
-	'\f': `\f`,
-	'\r': `\r`,
-	// Encode HTML specials as hex so the output can be embedded
-	// in HTML attributes without further encoding.
-	'"':  `\u0022`,
-	'&':  `\u0026`,
-	'\'': `\u0027`,
-	'+':  `\u002b`,
-	'/':  `\/`,
-	'<':  `\u003c`,
-	'>':  `\u003e`,
-	'\\': `\\`,
-}
-
-// jsStrNormReplacementTable is like jsStrReplacementTable but does not
-// overencode existing escapes since this table has no entry for `\`.
-var jsStrNormReplacementTable = []string{
-	0:    `\u0000`,
-	'\t': `\t`,
-	'\n': `\n`,
-	'\v': `\u000b`, // "\v" == "v" on IE 6.
-	'\f': `\f`,
-	'\r': `\r`,
-	// Encode HTML specials as hex so the output can be embedded
-	// in HTML attributes without further encoding.
-	'"':  `\u0022`,
-	'&':  `\u0026`,
-	'\'': `\u0027`,
-	'+':  `\u002b`,
-	'/':  `\/`,
-	'<':  `\u003c`,
-	'>':  `\u003e`,
-}
-var jsRegexpReplacementTable = []string{
-	0:    `\u0000`,
-	'\t': `\t`,
-	'\n': `\n`,
-	'\v': `\u000b`, // "\v" == "v" on IE 6.
-	'\f': `\f`,
-	'\r': `\r`,
-	// Encode HTML specials as hex so the output can be embedded
-	// in HTML attributes without further encoding.
-	'"':  `\u0022`,
-	'$':  `\$`,
-	'&':  `\u0026`,
-	'\'': `\u0027`,
-	'(':  `\(`,
-	')':  `\)`,
-	'*':  `\*`,
-	'+':  `\u002b`,
-	'-':  `\-`,
-	'.':  `\.`,
-	'/':  `\/`,
-	'<':  `\u003c`,
-	'>':  `\u003e`,
-	'?':  `\?`,
-	'[':  `\[`,
-	'\\': `\\`,
-	']':  `\]`,
-	'^':  `\^`,
-	'{':  `\{`,
-	'|':  `\|`,
-	'}':  `\}`,
-}
-
-// isJSIdentPart reports whether the given rune is a JS identifier part.
-// It does not handle all the non-Latin letters, joiners, and combining marks,
-// but it does handle every codepoint that can occur in a numeric literal or
-// a keyword.
-func isJSIdentPart(r rune) bool {
-	switch {
-	case r == '$':
-		return true
-	case '0' <= r && r <= '9':
-		return true
-	case 'A' <= r && r <= 'Z':
-		return true
-	case r == '_':
-		return true
-	case 'a' <= r && r <= 'z':
-		return true
-	}
-	return false
-}
-
-// isJSType reports whether the given MIME type should be considered JavaScript.
-//
-// It is used to determine whether a script tag with a type attribute is a javascript container.
-func isJSType(mimeType string) bool {
-	// per
-	//   https://www.w3.org/TR/html5/scripting-1.html#attr-script-type
-	//   https://tools.ietf.org/html/rfc7231#section-3.1.1
-	//   https://tools.ietf.org/html/rfc4329#section-3
-	//   https://www.ietf.org/rfc/rfc4627.txt
-	// discard parameters
-	if i := strings.Index(mimeType, ";"); i >= 0 {
-		mimeType = mimeType[:i]
-	}
-	mimeType = strings.ToLower(mimeType)
-	mimeType = strings.TrimSpace(mimeType)
-	switch mimeType {
-	case
-		"application/ecmascript",
-		"application/javascript",
-		"application/json",
-		"application/ld+json",
-		"application/x-ecmascript",
-		"application/x-javascript",
-		"module",
-		"text/ecmascript",
-		"text/javascript",
-		"text/javascript1.0",
-		"text/javascript1.1",
-		"text/javascript1.2",
-		"text/javascript1.3",
-		"text/javascript1.4",
-		"text/javascript1.5",
-		"text/jscript",
-		"text/livescript",
-		"text/x-ecmascript",
-		"text/x-javascript":
-		return true
-	default:
-		return false
-	}
-}
diff --git a/go.dev/cmd/internal/html/template/js_test.go b/go.dev/cmd/internal/html/template/js_test.go
deleted file mode 100644
index d7ee47b..0000000
--- a/go.dev/cmd/internal/html/template/js_test.go
+++ /dev/null
@@ -1,423 +0,0 @@
-// Copyright 2011 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 template
-
-import (
-	"bytes"
-	"math"
-	"strings"
-	"testing"
-)
-
-func TestNextJsCtx(t *testing.T) {
-	tests := []struct {
-		jsCtx jsCtx
-		s     string
-	}{
-		// Statement terminators precede regexps.
-		{jsCtxRegexp, ";"},
-		// This is not airtight.
-		//     ({ valueOf: function () { return 1 } } / 2)
-		// is valid JavaScript but in practice, devs do not do this.
-		// A block followed by a statement starting with a RegExp is
-		// much more common:
-		//     while (x) {...} /foo/.test(x) || panic()
-		{jsCtxRegexp, "}"},
-		// But member, call, grouping, and array expression terminators
-		// precede div ops.
-		{jsCtxDivOp, ")"},
-		{jsCtxDivOp, "]"},
-		// At the start of a primary expression, array, or expression
-		// statement, expect a regexp.
-		{jsCtxRegexp, "("},
-		{jsCtxRegexp, "["},
-		{jsCtxRegexp, "{"},
-		// Assignment operators precede regexps as do all exclusively
-		// prefix and binary operators.
-		{jsCtxRegexp, "="},
-		{jsCtxRegexp, "+="},
-		{jsCtxRegexp, "*="},
-		{jsCtxRegexp, "*"},
-		{jsCtxRegexp, "!"},
-		// Whether the + or - is infix or prefix, it cannot precede a
-		// div op.
-		{jsCtxRegexp, "+"},
-		{jsCtxRegexp, "-"},
-		// An incr/decr op precedes a div operator.
-		// This is not airtight. In (g = ++/h/i) a regexp follows a
-		// pre-increment operator, but in practice devs do not try to
-		// increment or decrement regular expressions.
-		// (g++/h/i) where ++ is a postfix operator on g is much more
-		// common.
-		{jsCtxDivOp, "--"},
-		{jsCtxDivOp, "++"},
-		{jsCtxDivOp, "x--"},
-		// When we have many dashes or pluses, then they are grouped
-		// left to right.
-		{jsCtxRegexp, "x---"}, // A postfix -- then a -.
-		// return followed by a slash returns the regexp literal or the
-		// slash starts a regexp literal in an expression statement that
-		// is dead code.
-		{jsCtxRegexp, "return"},
-		{jsCtxRegexp, "return "},
-		{jsCtxRegexp, "return\t"},
-		{jsCtxRegexp, "return\n"},
-		{jsCtxRegexp, "return\u2028"},
-		// Identifiers can be divided and cannot validly be preceded by
-		// a regular expressions. Semicolon insertion cannot happen
-		// between an identifier and a regular expression on a new line
-		// because the one token lookahead for semicolon insertion has
-		// to conclude that it could be a div binary op and treat it as
-		// such.
-		{jsCtxDivOp, "x"},
-		{jsCtxDivOp, "x "},
-		{jsCtxDivOp, "x\t"},
-		{jsCtxDivOp, "x\n"},
-		{jsCtxDivOp, "x\u2028"},
-		{jsCtxDivOp, "preturn"},
-		// Numbers precede div ops.
-		{jsCtxDivOp, "0"},
-		// Dots that are part of a number are div preceders.
-		{jsCtxDivOp, "0."},
-	}
-
-	for _, test := range tests {
-		if nextJSCtx([]byte(test.s), jsCtxRegexp) != test.jsCtx {
-			t.Errorf("want %s got %q", test.jsCtx, test.s)
-		}
-		if nextJSCtx([]byte(test.s), jsCtxDivOp) != test.jsCtx {
-			t.Errorf("want %s got %q", test.jsCtx, test.s)
-		}
-	}
-
-	if nextJSCtx([]byte("   "), jsCtxRegexp) != jsCtxRegexp {
-		t.Error("Blank tokens")
-	}
-
-	if nextJSCtx([]byte("   "), jsCtxDivOp) != jsCtxDivOp {
-		t.Error("Blank tokens")
-	}
-}
-
-func TestJSValEscaper(t *testing.T) {
-	tests := []struct {
-		x  interface{}
-		js string
-	}{
-		{int(42), " 42 "},
-		{uint(42), " 42 "},
-		{int16(42), " 42 "},
-		{uint16(42), " 42 "},
-		{int32(-42), " -42 "},
-		{uint32(42), " 42 "},
-		{int16(-42), " -42 "},
-		{uint16(42), " 42 "},
-		{int64(-42), " -42 "},
-		{uint64(42), " 42 "},
-		{uint64(1) << 53, " 9007199254740992 "},
-		// ulp(1 << 53) > 1 so this loses precision in JS
-		// but it is still a representable integer literal.
-		{uint64(1)<<53 + 1, " 9007199254740993 "},
-		{float32(1.0), " 1 "},
-		{float32(-1.0), " -1 "},
-		{float32(0.5), " 0.5 "},
-		{float32(-0.5), " -0.5 "},
-		{float32(1.0) / float32(256), " 0.00390625 "},
-		{float32(0), " 0 "},
-		{math.Copysign(0, -1), " -0 "},
-		{float64(1.0), " 1 "},
-		{float64(-1.0), " -1 "},
-		{float64(0.5), " 0.5 "},
-		{float64(-0.5), " -0.5 "},
-		{float64(0), " 0 "},
-		{math.Copysign(0, -1), " -0 "},
-		{"", `""`},
-		{"foo", `"foo"`},
-		// Newlines.
-		{"\r\n\u2028\u2029", `"\r\n\u2028\u2029"`},
-		// "\v" == "v" on IE 6 so use "\u000b" instead.
-		{"\t\x0b", `"\t\u000b"`},
-		{struct{ X, Y int }{1, 2}, `{"X":1,"Y":2}`},
-		{[]interface{}{}, "[]"},
-		{[]interface{}{42, "foo", nil}, `[42,"foo",null]`},
-		{[]string{"<!--", "</script>", "-->"}, `["\u003c!--","\u003c/script\u003e","--\u003e"]`},
-		{"<!--", `"\u003c!--"`},
-		{"-->", `"--\u003e"`},
-		{"<![CDATA[", `"\u003c![CDATA["`},
-		{"]]>", `"]]\u003e"`},
-		{"</script", `"\u003c/script"`},
-		{"\U0001D11E", "\"\U0001D11E\""}, // or "\uD834\uDD1E"
-		{nil, " null "},
-	}
-
-	for _, test := range tests {
-		if js := jsValEscaper(test.x); js != test.js {
-			t.Errorf("%+v: want\n\t%q\ngot\n\t%q", test.x, test.js, js)
-		}
-		// Make sure that escaping corner cases are not broken
-		// by nesting.
-		a := []interface{}{test.x}
-		want := "[" + strings.TrimSpace(test.js) + "]"
-		if js := jsValEscaper(a); js != want {
-			t.Errorf("%+v: want\n\t%q\ngot\n\t%q", a, want, js)
-		}
-	}
-}
-
-func TestJSStrEscaper(t *testing.T) {
-	tests := []struct {
-		x   interface{}
-		esc string
-	}{
-		{"", ``},
-		{"foo", `foo`},
-		{"\u0000", `\u0000`},
-		{"\t", `\t`},
-		{"\n", `\n`},
-		{"\r", `\r`},
-		{"\u2028", `\u2028`},
-		{"\u2029", `\u2029`},
-		{"\\", `\\`},
-		{"\\n", `\\n`},
-		{"foo\r\nbar", `foo\r\nbar`},
-		// Preserve attribute boundaries.
-		{`"`, `\u0022`},
-		{`'`, `\u0027`},
-		// Allow embedding in HTML without further escaping.
-		{`&amp;`, `\u0026amp;`},
-		// Prevent breaking out of text node and element boundaries.
-		{"</script>", `\u003c\/script\u003e`},
-		{"<![CDATA[", `\u003c![CDATA[`},
-		{"]]>", `]]\u003e`},
-		// https://dev.w3.org/html5/markup/aria/syntax.html#escaping-text-span
-		//   "The text in style, script, title, and textarea elements
-		//   must not have an escaping text span start that is not
-		//   followed by an escaping text span end."
-		// Furthermore, spoofing an escaping text span end could lead
-		// to different interpretation of a </script> sequence otherwise
-		// masked by the escaping text span, and spoofing a start could
-		// allow regular text content to be interpreted as script
-		// allowing script execution via a combination of a JS string
-		// injection followed by an HTML text injection.
-		{"<!--", `\u003c!--`},
-		{"-->", `--\u003e`},
-		// From https://code.google.com/p/doctype/wiki/ArticleUtf7
-		{"+ADw-script+AD4-alert(1)+ADw-/script+AD4-",
-			`\u002bADw-script\u002bAD4-alert(1)\u002bADw-\/script\u002bAD4-`,
-		},
-		// Invalid UTF-8 sequence
-		{"foo\xA0bar", "foo\xA0bar"},
-		// Invalid unicode scalar value.
-		{"foo\xed\xa0\x80bar", "foo\xed\xa0\x80bar"},
-	}
-
-	for _, test := range tests {
-		esc := jsStrEscaper(test.x)
-		if esc != test.esc {
-			t.Errorf("%q: want %q got %q", test.x, test.esc, esc)
-		}
-	}
-}
-
-func TestJSRegexpEscaper(t *testing.T) {
-	tests := []struct {
-		x   interface{}
-		esc string
-	}{
-		{"", `(?:)`},
-		{"foo", `foo`},
-		{"\u0000", `\u0000`},
-		{"\t", `\t`},
-		{"\n", `\n`},
-		{"\r", `\r`},
-		{"\u2028", `\u2028`},
-		{"\u2029", `\u2029`},
-		{"\\", `\\`},
-		{"\\n", `\\n`},
-		{"foo\r\nbar", `foo\r\nbar`},
-		// Preserve attribute boundaries.
-		{`"`, `\u0022`},
-		{`'`, `\u0027`},
-		// Allow embedding in HTML without further escaping.
-		{`&amp;`, `\u0026amp;`},
-		// Prevent breaking out of text node and element boundaries.
-		{"</script>", `\u003c\/script\u003e`},
-		{"<![CDATA[", `\u003c!\[CDATA\[`},
-		{"]]>", `\]\]\u003e`},
-		// Escaping text spans.
-		{"<!--", `\u003c!\-\-`},
-		{"-->", `\-\-\u003e`},
-		{"*", `\*`},
-		{"+", `\u002b`},
-		{"?", `\?`},
-		{"[](){}", `\[\]\(\)\{\}`},
-		{"$foo|x.y", `\$foo\|x\.y`},
-		{"x^y", `x\^y`},
-	}
-
-	for _, test := range tests {
-		esc := jsRegexpEscaper(test.x)
-		if esc != test.esc {
-			t.Errorf("%q: want %q got %q", test.x, test.esc, esc)
-		}
-	}
-}
-
-func TestEscapersOnLower7AndSelectHighCodepoints(t *testing.T) {
-	input := ("\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f" +
-		"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" +
-		` !"#$%&'()*+,-./` +
-		`0123456789:;<=>?` +
-		`@ABCDEFGHIJKLMNO` +
-		`PQRSTUVWXYZ[\]^_` +
-		"`abcdefghijklmno" +
-		"pqrstuvwxyz{|}~\x7f" +
-		"\u00A0\u0100\u2028\u2029\ufeff\U0001D11E")
-
-	tests := []struct {
-		name    string
-		escaper func(...interface{}) string
-		escaped string
-	}{
-		{
-			"jsStrEscaper",
-			jsStrEscaper,
-			`\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007` +
-				`\u0008\t\n\u000b\f\r\u000e\u000f` +
-				`\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017` +
-				`\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f` +
-				` !\u0022#$%\u0026\u0027()*\u002b,-.\/` +
-				`0123456789:;\u003c=\u003e?` +
-				`@ABCDEFGHIJKLMNO` +
-				`PQRSTUVWXYZ[\\]^_` +
-				"`abcdefghijklmno" +
-				"pqrstuvwxyz{|}~\u007f" +
-				"\u00A0\u0100\\u2028\\u2029\ufeff\U0001D11E",
-		},
-		{
-			"jsRegexpEscaper",
-			jsRegexpEscaper,
-			`\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007` +
-				`\u0008\t\n\u000b\f\r\u000e\u000f` +
-				`\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017` +
-				`\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f` +
-				` !\u0022#\$%\u0026\u0027\(\)\*\u002b,\-\.\/` +
-				`0123456789:;\u003c=\u003e\?` +
-				`@ABCDEFGHIJKLMNO` +
-				`PQRSTUVWXYZ\[\\\]\^_` +
-				"`abcdefghijklmno" +
-				`pqrstuvwxyz\{\|\}~` + "\u007f" +
-				"\u00A0\u0100\\u2028\\u2029\ufeff\U0001D11E",
-		},
-	}
-
-	for _, test := range tests {
-		if s := test.escaper(input); s != test.escaped {
-			t.Errorf("%s once: want\n\t%q\ngot\n\t%q", test.name, test.escaped, s)
-			continue
-		}
-
-		// Escape it rune by rune to make sure that any
-		// fast-path checking does not break escaping.
-		var buf bytes.Buffer
-		for _, c := range input {
-			buf.WriteString(test.escaper(string(c)))
-		}
-
-		if s := buf.String(); s != test.escaped {
-			t.Errorf("%s rune-wise: want\n\t%q\ngot\n\t%q", test.name, test.escaped, s)
-			continue
-		}
-	}
-}
-
-func TestIsJsMimeType(t *testing.T) {
-	tests := []struct {
-		in  string
-		out bool
-	}{
-		{"application/javascript;version=1.8", true},
-		{"application/javascript;version=1.8;foo=bar", true},
-		{"application/javascript/version=1.8", false},
-		{"text/javascript", true},
-		{"application/json", true},
-		{"application/ld+json", true},
-		{"module", true},
-	}
-
-	for _, test := range tests {
-		if isJSType(test.in) != test.out {
-			t.Errorf("isJSType(%q) = %v, want %v", test.in, !test.out, test.out)
-		}
-	}
-}
-
-func BenchmarkJSValEscaperWithNum(b *testing.B) {
-	for i := 0; i < b.N; i++ {
-		jsValEscaper(3.141592654)
-	}
-}
-
-func BenchmarkJSValEscaperWithStr(b *testing.B) {
-	for i := 0; i < b.N; i++ {
-		jsValEscaper("The <i>quick</i>,\r\n<span style='color:brown'>brown</span> fox jumps\u2028over the <canine class=\"lazy\">dog</canine>")
-	}
-}
-
-func BenchmarkJSValEscaperWithStrNoSpecials(b *testing.B) {
-	for i := 0; i < b.N; i++ {
-		jsValEscaper("The quick, brown fox jumps over the lazy dog")
-	}
-}
-
-func BenchmarkJSValEscaperWithObj(b *testing.B) {
-	o := struct {
-		S string
-		N int
-	}{
-		"The <i>quick</i>,\r\n<span style='color:brown'>brown</span> fox jumps\u2028over the <canine class=\"lazy\">dog</canine>\u2028",
-		42,
-	}
-	for i := 0; i < b.N; i++ {
-		jsValEscaper(o)
-	}
-}
-
-func BenchmarkJSValEscaperWithObjNoSpecials(b *testing.B) {
-	o := struct {
-		S string
-		N int
-	}{
-		"The quick, brown fox jumps over the lazy dog",
-		42,
-	}
-	for i := 0; i < b.N; i++ {
-		jsValEscaper(o)
-	}
-}
-
-func BenchmarkJSStrEscaperNoSpecials(b *testing.B) {
-	for i := 0; i < b.N; i++ {
-		jsStrEscaper("The quick, brown fox jumps over the lazy dog.")
-	}
-}
-
-func BenchmarkJSStrEscaper(b *testing.B) {
-	for i := 0; i < b.N; i++ {
-		jsStrEscaper("The <i>quick</i>,\r\n<span style='color:brown'>brown</span> fox jumps\u2028over the <canine class=\"lazy\">dog</canine>")
-	}
-}
-
-func BenchmarkJSRegexpEscaperNoSpecials(b *testing.B) {
-	for i := 0; i < b.N; i++ {
-		jsRegexpEscaper("The quick, brown fox jumps over the lazy dog")
-	}
-}
-
-func BenchmarkJSRegexpEscaper(b *testing.B) {
-	for i := 0; i < b.N; i++ {
-		jsRegexpEscaper("The <i>quick</i>,\r\n<span style='color:brown'>brown</span> fox jumps\u2028over the <canine class=\"lazy\">dog</canine>")
-	}
-}
diff --git a/go.dev/cmd/internal/html/template/jsctx_string.go b/go.dev/cmd/internal/html/template/jsctx_string.go
deleted file mode 100644
index dd1d87e..0000000
--- a/go.dev/cmd/internal/html/template/jsctx_string.go
+++ /dev/null
@@ -1,16 +0,0 @@
-// Code generated by "stringer -type jsCtx"; DO NOT EDIT.
-
-package template
-
-import "strconv"
-
-const _jsCtx_name = "jsCtxRegexpjsCtxDivOpjsCtxUnknown"
-
-var _jsCtx_index = [...]uint8{0, 11, 21, 33}
-
-func (i jsCtx) String() string {
-	if i >= jsCtx(len(_jsCtx_index)-1) {
-		return "jsCtx(" + strconv.FormatInt(int64(i), 10) + ")"
-	}
-	return _jsCtx_name[_jsCtx_index[i]:_jsCtx_index[i+1]]
-}
diff --git a/go.dev/cmd/internal/html/template/multi_test.go b/go.dev/cmd/internal/html/template/multi_test.go
deleted file mode 100644
index 30247ce..0000000
--- a/go.dev/cmd/internal/html/template/multi_test.go
+++ /dev/null
@@ -1,247 +0,0 @@
-// Copyright 2011 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.
-
-// Tests for multiple-template execution, copied from text/template.
-
-package template
-
-import (
-	"bytes"
-	"testing"
-
-	"golang.org/x/website/go.dev/cmd/internal/text/template/parse"
-)
-
-var multiExecTests = []execTest{
-	{"empty", "", "", nil, true},
-	{"text", "some text", "some text", nil, true},
-	{"invoke x", `{{template "x" .SI}}`, "TEXT", tVal, true},
-	{"invoke x no args", `{{template "x"}}`, "TEXT", tVal, true},
-	{"invoke dot int", `{{template "dot" .I}}`, "17", tVal, true},
-	{"invoke dot []int", `{{template "dot" .SI}}`, "[3 4 5]", tVal, true},
-	{"invoke dotV", `{{template "dotV" .U}}`, "v", tVal, true},
-	{"invoke nested int", `{{template "nested" .I}}`, "17", tVal, true},
-	{"variable declared by template", `{{template "nested" $x:=.SI}},{{index $x 1}}`, "[3 4 5],4", tVal, true},
-
-	// User-defined function: test argument evaluator.
-	{"testFunc literal", `{{oneArg "joe"}}`, "oneArg=joe", tVal, true},
-	{"testFunc .", `{{oneArg .}}`, "oneArg=joe", "joe", true},
-}
-
-// These strings are also in testdata/*.
-const multiText1 = `
-	{{define "x"}}TEXT{{end}}
-	{{define "dotV"}}{{.V}}{{end}}
-`
-
-const multiText2 = `
-	{{define "dot"}}{{.}}{{end}}
-	{{define "nested"}}{{template "dot" .}}{{end}}
-`
-
-func TestMultiExecute(t *testing.T) {
-	// Declare a couple of templates first.
-	template, err := New("root").Parse(multiText1)
-	if err != nil {
-		t.Fatalf("parse error for 1: %s", err)
-	}
-	_, err = template.Parse(multiText2)
-	if err != nil {
-		t.Fatalf("parse error for 2: %s", err)
-	}
-	testExecute(multiExecTests, template, t)
-}
-
-func TestParseFiles(t *testing.T) {
-	_, err := ParseFiles("DOES NOT EXIST")
-	if err == nil {
-		t.Error("expected error for non-existent file; got none")
-	}
-	template := New("root")
-	_, err = template.ParseFiles("testdata/file1.tmpl", "testdata/file2.tmpl")
-	if err != nil {
-		t.Fatalf("error parsing files: %v", err)
-	}
-	testExecute(multiExecTests, template, t)
-}
-
-func TestParseGlob(t *testing.T) {
-	_, err := ParseGlob("DOES NOT EXIST")
-	if err == nil {
-		t.Error("expected error for non-existent file; got none")
-	}
-	_, err = New("error").ParseGlob("[x")
-	if err == nil {
-		t.Error("expected error for bad pattern; got none")
-	}
-	template := New("root")
-	_, err = template.ParseGlob("testdata/file*.tmpl")
-	if err != nil {
-		t.Fatalf("error parsing files: %v", err)
-	}
-	testExecute(multiExecTests, template, t)
-}
-
-// In these tests, actual content (not just template definitions) comes from the parsed files.
-
-var templateFileExecTests = []execTest{
-	{"test", `{{template "tmpl1.tmpl"}}{{template "tmpl2.tmpl"}}`, "template1\n\ny\ntemplate2\n\nx\n", 0, true},
-}
-
-func TestParseFilesWithData(t *testing.T) {
-	template, err := New("root").ParseFiles("testdata/tmpl1.tmpl", "testdata/tmpl2.tmpl")
-	if err != nil {
-		t.Fatalf("error parsing files: %v", err)
-	}
-	testExecute(templateFileExecTests, template, t)
-}
-
-func TestParseGlobWithData(t *testing.T) {
-	template, err := New("root").ParseGlob("testdata/tmpl*.tmpl")
-	if err != nil {
-		t.Fatalf("error parsing files: %v", err)
-	}
-	testExecute(templateFileExecTests, template, t)
-}
-
-const (
-	cloneText1 = `{{define "a"}}{{template "b"}}{{template "c"}}{{end}}`
-	cloneText2 = `{{define "b"}}b{{end}}`
-	cloneText3 = `{{define "c"}}root{{end}}`
-	cloneText4 = `{{define "c"}}clone{{end}}`
-)
-
-// Issue 7032
-func TestAddParseTreeToUnparsedTemplate(t *testing.T) {
-	master := "{{define \"master\"}}{{end}}"
-	tmpl := New("master")
-	tree, err := parse.Parse("master", master, "", "", nil)
-	if err != nil {
-		t.Fatalf("unexpected parse err: %v", err)
-	}
-	masterTree := tree["master"]
-	tmpl.AddParseTree("master", masterTree) // used to panic
-}
-
-func TestRedefinition(t *testing.T) {
-	var tmpl *Template
-	var err error
-	if tmpl, err = New("tmpl1").Parse(`{{define "test"}}foo{{end}}`); err != nil {
-		t.Fatalf("parse 1: %v", err)
-	}
-	if _, err = tmpl.Parse(`{{define "test"}}bar{{end}}`); err != nil {
-		t.Fatalf("got error %v, expected nil", err)
-	}
-	if _, err = tmpl.New("tmpl2").Parse(`{{define "test"}}bar{{end}}`); err != nil {
-		t.Fatalf("got error %v, expected nil", err)
-	}
-}
-
-// Issue 10879
-func TestEmptyTemplateCloneCrash(t *testing.T) {
-	t1 := New("base")
-	t1.Clone() // used to panic
-}
-
-// Issue 10910, 10926
-func TestTemplateLookUp(t *testing.T) {
-	t.Skip("broken on html/template") // TODO
-	t1 := New("foo")
-	if t1.Lookup("foo") != nil {
-		t.Error("Lookup returned non-nil value for undefined template foo")
-	}
-	t1.New("bar")
-	if t1.Lookup("bar") != nil {
-		t.Error("Lookup returned non-nil value for undefined template bar")
-	}
-	t1.Parse(`{{define "foo"}}test{{end}}`)
-	if t1.Lookup("foo") == nil {
-		t.Error("Lookup returned nil value for defined template")
-	}
-}
-
-func TestParse(t *testing.T) {
-	// In multiple calls to Parse with the same receiver template, only one call
-	// can contain text other than space, comments, and template definitions
-	t1 := New("test")
-	if _, err := t1.Parse(`{{define "test"}}{{end}}`); err != nil {
-		t.Fatalf("parsing test: %s", err)
-	}
-	if _, err := t1.Parse(`{{define "test"}}{{/* this is a comment */}}{{end}}`); err != nil {
-		t.Fatalf("parsing test: %s", err)
-	}
-	if _, err := t1.Parse(`{{define "test"}}foo{{end}}`); err != nil {
-		t.Fatalf("parsing test: %s", err)
-	}
-}
-
-func TestEmptyTemplate(t *testing.T) {
-	cases := []struct {
-		defn []string
-		in   string
-		want string
-	}{
-		{[]string{"x", "y"}, "", "y"},
-		{[]string{""}, "once", ""},
-		{[]string{"", ""}, "twice", ""},
-		{[]string{"{{.}}", "{{.}}"}, "twice", "twice"},
-		{[]string{"{{/* a comment */}}", "{{/* a comment */}}"}, "comment", ""},
-		{[]string{"{{.}}", ""}, "twice", "twice"}, // TODO: should want "" not "twice"
-	}
-
-	for i, c := range cases {
-		root := New("root")
-
-		var (
-			m   *Template
-			err error
-		)
-		for _, d := range c.defn {
-			m, err = root.New(c.in).Parse(d)
-			if err != nil {
-				t.Fatal(err)
-			}
-		}
-		buf := &bytes.Buffer{}
-		if err := m.Execute(buf, c.in); err != nil {
-			t.Error(i, err)
-			continue
-		}
-		if buf.String() != c.want {
-			t.Errorf("expected string %q: got %q", c.want, buf.String())
-		}
-	}
-}
-
-// Issue 19249 was a regression in 1.8 caused by the handling of empty
-// templates added in that release, which got different answers depending
-// on the order templates appeared in the internal map.
-func TestIssue19294(t *testing.T) {
-	// The empty block in "xhtml" should be replaced during execution
-	// by the contents of "stylesheet", but if the internal map associating
-	// names with templates is built in the wrong order, the empty block
-	// looks non-empty and this doesn't happen.
-	var inlined = map[string]string{
-		"stylesheet": `{{define "stylesheet"}}stylesheet{{end}}`,
-		"xhtml":      `{{block "stylesheet" .}}{{end}}`,
-	}
-	all := []string{"stylesheet", "xhtml"}
-	for i := 0; i < 100; i++ {
-		res, err := New("title.xhtml").Parse(`{{template "xhtml" .}}`)
-		if err != nil {
-			t.Fatal(err)
-		}
-		for _, name := range all {
-			_, err := res.New(name).Parse(inlined[name])
-			if err != nil {
-				t.Fatal(err)
-			}
-		}
-		var buf bytes.Buffer
-		res.Execute(&buf, 0)
-		if buf.String() != "stylesheet" {
-			t.Fatalf("iteration %d: got %q; expected %q", i, buf.String(), "stylesheet")
-		}
-	}
-}
diff --git a/go.dev/cmd/internal/html/template/state_string.go b/go.dev/cmd/internal/html/template/state_string.go
deleted file mode 100644
index 05104be..0000000
--- a/go.dev/cmd/internal/html/template/state_string.go
+++ /dev/null
@@ -1,16 +0,0 @@
-// Code generated by "stringer -type state"; DO NOT EDIT.
-
-package template
-
-import "strconv"
-
-const _state_name = "stateTextstateTagstateAttrNamestateAfterNamestateBeforeValuestateHTMLCmtstateRCDATAstateAttrstateURLstateSrcsetstateJSstateJSDqStrstateJSSqStrstateJSRegexpstateJSBlockCmtstateJSLineCmtstateCSSstateCSSDqStrstateCSSSqStrstateCSSDqURLstateCSSSqURLstateCSSURLstateCSSBlockCmtstateCSSLineCmtstateError"
-
-var _state_index = [...]uint16{0, 9, 17, 30, 44, 60, 72, 83, 92, 100, 111, 118, 130, 142, 155, 170, 184, 192, 205, 218, 231, 244, 255, 271, 286, 296}
-
-func (i state) String() string {
-	if i >= state(len(_state_index)-1) {
-		return "state(" + strconv.FormatInt(int64(i), 10) + ")"
-	}
-	return _state_name[_state_index[i]:_state_index[i+1]]
-}
diff --git a/go.dev/cmd/internal/html/template/template.go b/go.dev/cmd/internal/html/template/template.go
deleted file mode 100644
index 1de4bd5..0000000
--- a/go.dev/cmd/internal/html/template/template.go
+++ /dev/null
@@ -1,496 +0,0 @@
-// Copyright 2011 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 template
-
-import (
-	"fmt"
-	"io"
-	"io/ioutil"
-	"path/filepath"
-	"sync"
-
-	"golang.org/x/website/go.dev/cmd/internal/text/template"
-	"golang.org/x/website/go.dev/cmd/internal/text/template/parse"
-)
-
-// Template is a specialized Template from "golang.org/x/website/go.dev/cmd/internal/text/template" that produces a safe
-// HTML document fragment.
-type Template struct {
-	// Sticky error if escaping fails, or escapeOK if succeeded.
-	escapeErr error
-	// We could embed the text/template field, but it's safer not to because
-	// we need to keep our version of the name space and the underlying
-	// template's in sync.
-	text *template.Template
-	// The underlying template's parse tree, updated to be HTML-safe.
-	Tree       *parse.Tree
-	*nameSpace // common to all associated templates
-}
-
-// escapeOK is a sentinel value used to indicate valid escaping.
-var escapeOK = fmt.Errorf("template escaped correctly")
-
-// nameSpace is the data structure shared by all templates in an association.
-type nameSpace struct {
-	mu      sync.Mutex
-	set     map[string]*Template
-	escaped bool
-	esc     escaper
-}
-
-// Templates returns a slice of the templates associated with t, including t
-// itself.
-func (t *Template) Templates() []*Template {
-	ns := t.nameSpace
-	ns.mu.Lock()
-	defer ns.mu.Unlock()
-	// Return a slice so we don't expose the map.
-	m := make([]*Template, 0, len(ns.set))
-	for _, v := range ns.set {
-		m = append(m, v)
-	}
-	return m
-}
-
-// Option sets options for the template. Options are described by
-// strings, either a simple string or "key=value". There can be at
-// most one equals sign in an option string. If the option string
-// is unrecognized or otherwise invalid, Option panics.
-//
-// Known options:
-//
-// missingkey: Control the behavior during execution if a map is
-// indexed with a key that is not present in the map.
-//	"missingkey=default" or "missingkey=invalid"
-//		The default behavior: Do nothing and continue execution.
-//		If printed, the result of the index operation is the string
-//		"<no value>".
-//	"missingkey=zero"
-//		The operation returns the zero value for the map type's element.
-//	"missingkey=error"
-//		Execution stops immediately with an error.
-//
-func (t *Template) Option(opt ...string) *Template {
-	t.text.Option(opt...)
-	return t
-}
-
-// checkCanParse checks whether it is OK to parse templates.
-// If not, it returns an error.
-func (t *Template) checkCanParse() error {
-	if t == nil {
-		return nil
-	}
-	t.nameSpace.mu.Lock()
-	defer t.nameSpace.mu.Unlock()
-	if t.nameSpace.escaped {
-		return fmt.Errorf("golang.org/x/website/go.dev/cmd/internal/html/template: cannot Parse after Execute")
-	}
-	return nil
-}
-
-// escape escapes all associated templates.
-func (t *Template) escape() error {
-	t.nameSpace.mu.Lock()
-	defer t.nameSpace.mu.Unlock()
-	t.nameSpace.escaped = true
-	if t.escapeErr == nil {
-		if t.Tree == nil {
-			return fmt.Errorf("template: %q is an incomplete or empty template", t.Name())
-		}
-		if err := escapeTemplate(t, t.text.Root, t.Name()); err != nil {
-			return err
-		}
-	} else if t.escapeErr != escapeOK {
-		return t.escapeErr
-	}
-	return nil
-}
-
-// Execute applies a parsed template to the specified data object,
-// writing the output to wr.
-// If an error occurs executing the template or writing its output,
-// execution stops, but partial results may already have been written to
-// the output writer.
-// A template may be executed safely in parallel, although if parallel
-// executions share a Writer the output may be interleaved.
-func (t *Template) Execute(wr io.Writer, data interface{}) error {
-	if err := t.escape(); err != nil {
-		return err
-	}
-	return t.text.Execute(wr, data)
-}
-
-// ExecuteTemplate applies the template associated with t that has the given
-// name to the specified data object and writes the output to wr.
-// If an error occurs executing the template or writing its output,
-// execution stops, but partial results may already have been written to
-// the output writer.
-// A template may be executed safely in parallel, although if parallel
-// executions share a Writer the output may be interleaved.
-func (t *Template) ExecuteTemplate(wr io.Writer, name string, data interface{}) error {
-	tmpl, err := t.lookupAndEscapeTemplate(name)
-	if err != nil {
-		return err
-	}
-	return tmpl.text.Execute(wr, data)
-}
-
-// lookupAndEscapeTemplate guarantees that the template with the given name
-// is escaped, or returns an error if it cannot be. It returns the named
-// template.
-func (t *Template) lookupAndEscapeTemplate(name string) (tmpl *Template, err error) {
-	t.nameSpace.mu.Lock()
-	defer t.nameSpace.mu.Unlock()
-	t.nameSpace.escaped = true
-	tmpl = t.set[name]
-	if tmpl == nil {
-		return nil, fmt.Errorf("golang.org/x/website/go.dev/cmd/internal/html/template: %q is undefined", name)
-	}
-	if tmpl.escapeErr != nil && tmpl.escapeErr != escapeOK {
-		return nil, tmpl.escapeErr
-	}
-	if tmpl.text.Tree == nil || tmpl.text.Root == nil {
-		return nil, fmt.Errorf("golang.org/x/website/go.dev/cmd/internal/html/template: %q is an incomplete template", name)
-	}
-	if t.text.Lookup(name) == nil {
-		panic("golang.org/x/website/go.dev/cmd/internal/html/template internal error: template escaping out of sync")
-	}
-	if tmpl.escapeErr == nil {
-		err = escapeTemplate(tmpl, tmpl.text.Root, name)
-	}
-	return tmpl, err
-}
-
-// DefinedTemplates returns a string listing the defined templates,
-// prefixed by the string "; defined templates are: ". If there are none,
-// it returns the empty string. Used to generate an error message.
-func (t *Template) DefinedTemplates() string {
-	return t.text.DefinedTemplates()
-}
-
-// Parse parses text as a template body for t.
-// Named template definitions ({{define ...}} or {{block ...}} statements) in text
-// define additional templates associated with t and are removed from the
-// definition of t itself.
-//
-// Templates can be redefined in successive calls to Parse,
-// before the first use of Execute on t or any associated template.
-// A template definition with a body containing only white space and comments
-// is considered empty and will not replace an existing template's body.
-// This allows using Parse to add new named template definitions without
-// overwriting the main template body.
-func (t *Template) Parse(text string) (*Template, error) {
-	if err := t.checkCanParse(); err != nil {
-		return nil, err
-	}
-
-	ret, err := t.text.Parse(text)
-	if err != nil {
-		return nil, err
-	}
-
-	// In general, all the named templates might have changed underfoot.
-	// Regardless, some new ones may have been defined.
-	// The template.Template set has been updated; update ours.
-	t.nameSpace.mu.Lock()
-	defer t.nameSpace.mu.Unlock()
-	for _, v := range ret.Templates() {
-		name := v.Name()
-		tmpl := t.set[name]
-		if tmpl == nil {
-			tmpl = t.new(name)
-		}
-		tmpl.text = v
-		tmpl.Tree = v.Tree
-	}
-	return t, nil
-}
-
-// AddParseTree creates a new template with the name and parse tree
-// and associates it with t.
-//
-// It returns an error if t or any associated template has already been executed.
-func (t *Template) AddParseTree(name string, tree *parse.Tree) (*Template, error) {
-	if err := t.checkCanParse(); err != nil {
-		return nil, err
-	}
-
-	t.nameSpace.mu.Lock()
-	defer t.nameSpace.mu.Unlock()
-	text, err := t.text.AddParseTree(name, tree)
-	if err != nil {
-		return nil, err
-	}
-	ret := &Template{
-		nil,
-		text,
-		text.Tree,
-		t.nameSpace,
-	}
-	t.set[name] = ret
-	return ret, nil
-}
-
-// Clone returns a duplicate of the template, including all associated
-// templates. The actual representation is not copied, but the name space of
-// associated templates is, so further calls to Parse in the copy will add
-// templates to the copy but not to the original. Clone can be used to prepare
-// common templates and use them with variant definitions for other templates
-// by adding the variants after the clone is made.
-//
-// It returns an error if t has already been executed.
-func (t *Template) Clone() (*Template, error) {
-	t.nameSpace.mu.Lock()
-	defer t.nameSpace.mu.Unlock()
-	if t.escapeErr != nil {
-		return nil, fmt.Errorf("golang.org/x/website/go.dev/cmd/internal/html/template: cannot Clone %q after it has executed", t.Name())
-	}
-	textClone, err := t.text.Clone()
-	if err != nil {
-		return nil, err
-	}
-	ns := &nameSpace{set: make(map[string]*Template)}
-	ns.esc = makeEscaper(ns)
-	ret := &Template{
-		nil,
-		textClone,
-		textClone.Tree,
-		ns,
-	}
-	ret.set[ret.Name()] = ret
-	for _, x := range textClone.Templates() {
-		name := x.Name()
-		src := t.set[name]
-		if src == nil || src.escapeErr != nil {
-			return nil, fmt.Errorf("golang.org/x/website/go.dev/cmd/internal/html/template: cannot Clone %q after it has executed", t.Name())
-		}
-		x.Tree = x.Tree.Copy()
-		ret.set[name] = &Template{
-			nil,
-			x,
-			x.Tree,
-			ret.nameSpace,
-		}
-	}
-	// Return the template associated with the name of this template.
-	return ret.set[ret.Name()], nil
-}
-
-// New allocates a new HTML template with the given name.
-func New(name string) *Template {
-	ns := &nameSpace{set: make(map[string]*Template)}
-	ns.esc = makeEscaper(ns)
-	tmpl := &Template{
-		nil,
-		template.New(name),
-		nil,
-		ns,
-	}
-	tmpl.set[name] = tmpl
-	return tmpl
-}
-
-// New allocates a new HTML template associated with the given one
-// and with the same delimiters. The association, which is transitive,
-// allows one template to invoke another with a {{template}} action.
-//
-// If a template with the given name already exists, the new HTML template
-// will replace it. The existing template will be reset and disassociated with
-// t.
-func (t *Template) New(name string) *Template {
-	t.nameSpace.mu.Lock()
-	defer t.nameSpace.mu.Unlock()
-	return t.new(name)
-}
-
-// new is the implementation of New, without the lock.
-func (t *Template) new(name string) *Template {
-	tmpl := &Template{
-		nil,
-		t.text.New(name),
-		nil,
-		t.nameSpace,
-	}
-	if existing, ok := tmpl.set[name]; ok {
-		emptyTmpl := New(existing.Name())
-		*existing = *emptyTmpl
-	}
-	tmpl.set[name] = tmpl
-	return tmpl
-}
-
-// Name returns the name of the template.
-func (t *Template) Name() string {
-	return t.text.Name()
-}
-
-// FuncMap is the type of the map defining the mapping from names to
-// functions. Each function must have either a single return value, or two
-// return values of which the second has type error. In that case, if the
-// second (error) argument evaluates to non-nil during execution, execution
-// terminates and Execute returns that error. FuncMap has the same base type
-// as FuncMap in "golang.org/x/website/go.dev/cmd/internal/text/template", copied here so clients need not import
-// "golang.org/x/website/go.dev/cmd/internal/text/template".
-type FuncMap map[string]interface{}
-
-// Funcs adds the elements of the argument map to the template's function map.
-// It must be called before the template is parsed.
-// It panics if a value in the map is not a function with appropriate return
-// type. However, it is legal to overwrite elements of the map. The return
-// value is the template, so calls can be chained.
-func (t *Template) Funcs(funcMap FuncMap) *Template {
-	t.text.Funcs(template.FuncMap(funcMap))
-	return t
-}
-
-// Delims sets the action delimiters to the specified strings, to be used in
-// subsequent calls to Parse, ParseFiles, or ParseGlob. Nested template
-// definitions will inherit the settings. An empty delimiter stands for the
-// corresponding default: {{ or }}.
-// The return value is the template, so calls can be chained.
-func (t *Template) Delims(left, right string) *Template {
-	t.text.Delims(left, right)
-	return t
-}
-
-// Lookup returns the template with the given name that is associated with t,
-// or nil if there is no such template.
-func (t *Template) Lookup(name string) *Template {
-	t.nameSpace.mu.Lock()
-	defer t.nameSpace.mu.Unlock()
-	return t.set[name]
-}
-
-// Must is a helper that wraps a call to a function returning (*Template, error)
-// and panics if the error is non-nil. It is intended for use in variable initializations
-// such as
-//	var t = template.Must(template.New("name").Parse("html"))
-func Must(t *Template, err error) *Template {
-	if err != nil {
-		panic(err)
-	}
-	return t
-}
-
-// ParseFiles creates a new Template and parses the template definitions from
-// the named files. The returned template's name will have the (base) name and
-// (parsed) contents of the first file. There must be at least one file.
-// If an error occurs, parsing stops and the returned *Template is nil.
-//
-// When parsing multiple files with the same name in different directories,
-// the last one mentioned will be the one that results.
-// For instance, ParseFiles("a/foo", "b/foo") stores "b/foo" as the template
-// named "foo", while "a/foo" is unavailable.
-func ParseFiles(filenames ...string) (*Template, error) {
-	return parseFiles(nil, readFileOS, filenames...)
-}
-
-// ParseFiles parses the named files and associates the resulting templates with
-// t. If an error occurs, parsing stops and the returned template is nil;
-// otherwise it is t. There must be at least one file.
-//
-// When parsing multiple files with the same name in different directories,
-// the last one mentioned will be the one that results.
-//
-// ParseFiles returns an error if t or any associated template has already been executed.
-func (t *Template) ParseFiles(filenames ...string) (*Template, error) {
-	return parseFiles(t, readFileOS, filenames...)
-}
-
-// parseFiles is the helper for the method and function. If the argument
-// template is nil, it is created from the first file.
-func parseFiles(t *Template, readFile func(string) (string, []byte, error), filenames ...string) (*Template, error) {
-	if err := t.checkCanParse(); err != nil {
-		return nil, err
-	}
-
-	if len(filenames) == 0 {
-		// Not really a problem, but be consistent.
-		return nil, fmt.Errorf("golang.org/x/website/go.dev/cmd/internal/html/template: no files named in call to ParseFiles")
-	}
-	for _, filename := range filenames {
-		name, b, err := readFile(filename)
-		if err != nil {
-			return nil, err
-		}
-		s := string(b)
-		// First template becomes return value if not already defined,
-		// and we use that one for subsequent New calls to associate
-		// all the templates together. Also, if this file has the same name
-		// as t, this file becomes the contents of t, so
-		//  t, err := New(name).Funcs(xxx).ParseFiles(name)
-		// works. Otherwise we create a new template associated with t.
-		var tmpl *Template
-		if t == nil {
-			t = New(name)
-		}
-		if name == t.Name() {
-			tmpl = t
-		} else {
-			tmpl = t.New(name)
-		}
-		_, err = tmpl.Parse(s)
-		if err != nil {
-			return nil, err
-		}
-	}
-	return t, nil
-}
-
-// ParseGlob creates a new Template and parses the template definitions from
-// the files identified by the pattern. The files are matched according to the
-// semantics of filepath.Match, and the pattern must match at least one file.
-// The returned template will have the (base) name and (parsed) contents of the
-// first file matched by the pattern. ParseGlob is equivalent to calling
-// ParseFiles with the list of files matched by the pattern.
-//
-// When parsing multiple files with the same name in different directories,
-// the last one mentioned will be the one that results.
-func ParseGlob(pattern string) (*Template, error) {
-	return parseGlob(nil, pattern)
-}
-
-// ParseGlob parses the template definitions in the files identified by the
-// pattern and associates the resulting templates with t. The files are matched
-// according to the semantics of filepath.Match, and the pattern must match at
-// least one file. ParseGlob is equivalent to calling t.ParseFiles with the
-// list of files matched by the pattern.
-//
-// When parsing multiple files with the same name in different directories,
-// the last one mentioned will be the one that results.
-//
-// ParseGlob returns an error if t or any associated template has already been executed.
-func (t *Template) ParseGlob(pattern string) (*Template, error) {
-	return parseGlob(t, pattern)
-}
-
-// parseGlob is the implementation of the function and method ParseGlob.
-func parseGlob(t *Template, pattern string) (*Template, error) {
-	if err := t.checkCanParse(); err != nil {
-		return nil, err
-	}
-	filenames, err := filepath.Glob(pattern)
-	if err != nil {
-		return nil, err
-	}
-	if len(filenames) == 0 {
-		return nil, fmt.Errorf("golang.org/x/website/go.dev/cmd/internal/html/template: pattern matches no files: %#q", pattern)
-	}
-	return parseFiles(t, readFileOS, filenames...)
-}
-
-// IsTrue reports whether the value is 'true', in the sense of not the zero of its type,
-// and whether the value has a meaningful truth value. This is the definition of
-// truth used by if and other such actions.
-func IsTrue(val interface{}) (truth, ok bool) {
-	return template.IsTrue(val)
-}
-
-func readFileOS(file string) (name string, b []byte, err error) {
-	name = filepath.Base(file)
-	b, err = ioutil.ReadFile(file)
-	return
-}
diff --git a/go.dev/cmd/internal/html/template/template_test.go b/go.dev/cmd/internal/html/template/template_test.go
deleted file mode 100644
index c04c43e..0000000
--- a/go.dev/cmd/internal/html/template/template_test.go
+++ /dev/null
@@ -1,219 +0,0 @@
-// Copyright 2016 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 template_test
-
-import (
-	"bytes"
-	"encoding/json"
-	"strings"
-	"testing"
-
-	. "golang.org/x/website/go.dev/cmd/internal/html/template"
-	"golang.org/x/website/go.dev/cmd/internal/text/template/parse"
-)
-
-func TestTemplateClone(t *testing.T) {
-	// https://golang.org/issue/12996
-	orig := New("name")
-	clone, err := orig.Clone()
-	if err != nil {
-		t.Fatal(err)
-	}
-	if len(clone.Templates()) != len(orig.Templates()) {
-		t.Fatalf("Invalid length of t.Clone().Templates()")
-	}
-
-	const want = "stuff"
-	parsed := Must(clone.Parse(want))
-	var buf bytes.Buffer
-	err = parsed.Execute(&buf, nil)
-	if err != nil {
-		t.Fatal(err)
-	}
-	if got := buf.String(); got != want {
-		t.Fatalf("got %q; want %q", got, want)
-	}
-}
-
-func TestRedefineNonEmptyAfterExecution(t *testing.T) {
-	c := newTestCase(t)
-	c.mustParse(c.root, `foo`)
-	c.mustExecute(c.root, nil, "foo")
-	c.mustNotParse(c.root, `bar`)
-}
-
-func TestRedefineEmptyAfterExecution(t *testing.T) {
-	c := newTestCase(t)
-	c.mustParse(c.root, ``)
-	c.mustExecute(c.root, nil, "")
-	c.mustNotParse(c.root, `foo`)
-	c.mustExecute(c.root, nil, "")
-}
-
-func TestRedefineAfterNonExecution(t *testing.T) {
-	c := newTestCase(t)
-	c.mustParse(c.root, `{{if .}}<{{template "X"}}>{{end}}{{define "X"}}foo{{end}}`)
-	c.mustExecute(c.root, 0, "")
-	c.mustNotParse(c.root, `{{define "X"}}bar{{end}}`)
-	c.mustExecute(c.root, 1, "&lt;foo>")
-}
-
-func TestRedefineAfterNamedExecution(t *testing.T) {
-	c := newTestCase(t)
-	c.mustParse(c.root, `<{{template "X" .}}>{{define "X"}}foo{{end}}`)
-	c.mustExecute(c.root, nil, "&lt;foo>")
-	c.mustNotParse(c.root, `{{define "X"}}bar{{end}}`)
-	c.mustExecute(c.root, nil, "&lt;foo>")
-}
-
-func TestRedefineNestedByNameAfterExecution(t *testing.T) {
-	c := newTestCase(t)
-	c.mustParse(c.root, `{{define "X"}}foo{{end}}`)
-	c.mustExecute(c.lookup("X"), nil, "foo")
-	c.mustNotParse(c.root, `{{define "X"}}bar{{end}}`)
-	c.mustExecute(c.lookup("X"), nil, "foo")
-}
-
-func TestRedefineNestedByTemplateAfterExecution(t *testing.T) {
-	c := newTestCase(t)
-	c.mustParse(c.root, `{{define "X"}}foo{{end}}`)
-	c.mustExecute(c.lookup("X"), nil, "foo")
-	c.mustNotParse(c.lookup("X"), `bar`)
-	c.mustExecute(c.lookup("X"), nil, "foo")
-}
-
-func TestRedefineSafety(t *testing.T) {
-	c := newTestCase(t)
-	c.mustParse(c.root, `<html><a href="{{template "X"}}">{{define "X"}}{{end}}`)
-	c.mustExecute(c.root, nil, `<html><a href="">`)
-	// Note: Every version of Go prior to Go 1.8 accepted the redefinition of "X"
-	// on the next line, but luckily kept it from being used in the outer template.
-	// Now we reject it, which makes clearer that we're not going to use it.
-	c.mustNotParse(c.root, `{{define "X"}}" bar="baz{{end}}`)
-	c.mustExecute(c.root, nil, `<html><a href="">`)
-}
-
-func TestRedefineTopUse(t *testing.T) {
-	c := newTestCase(t)
-	c.mustParse(c.root, `{{template "X"}}{{.}}{{define "X"}}{{end}}`)
-	c.mustExecute(c.root, 42, `42`)
-	c.mustNotParse(c.root, `{{define "X"}}<script>{{end}}`)
-	c.mustExecute(c.root, 42, `42`)
-}
-
-func TestRedefineOtherParsers(t *testing.T) {
-	c := newTestCase(t)
-	c.mustParse(c.root, ``)
-	c.mustExecute(c.root, nil, ``)
-	if _, err := c.root.ParseFiles("no.template"); err == nil || !strings.Contains(err.Error(), "Execute") {
-		t.Errorf("ParseFiles: %v\nwanted error about already having Executed", err)
-	}
-	if _, err := c.root.ParseGlob("*.no.template"); err == nil || !strings.Contains(err.Error(), "Execute") {
-		t.Errorf("ParseGlob: %v\nwanted error about already having Executed", err)
-	}
-	if _, err := c.root.AddParseTree("t1", c.root.Tree); err == nil || !strings.Contains(err.Error(), "Execute") {
-		t.Errorf("AddParseTree: %v\nwanted error about already having Executed", err)
-	}
-}
-
-func TestNumbers(t *testing.T) {
-	c := newTestCase(t)
-	c.mustParse(c.root, `{{print 1_2.3_4}} {{print 0x0_1.e_0p+02}}`)
-	c.mustExecute(c.root, nil, "12.34 7.5")
-}
-
-func TestStringsInScriptsWithJsonContentTypeAreCorrectlyEscaped(t *testing.T) {
-	// See #33671 and #37634 for more context on this.
-	tests := []struct{ name, in string }{
-		{"empty", ""},
-		{"invalid", string(rune(-1))},
-		{"null", "\u0000"},
-		{"unit separator", "\u001F"},
-		{"tab", "\t"},
-		{"gt and lt", "<>"},
-		{"quotes", `'"`},
-		{"ASCII letters", "ASCII letters"},
-		{"Unicode", "ʕ⊙ϖ⊙ʔ"},
-		{"Pizza", "🍕"},
-	}
-	const (
-		prefix = `<script type="application/ld+json">`
-		suffix = `</script>`
-		templ  = prefix + `"{{.}}"` + suffix
-	)
-	tpl := Must(New("JS string is JSON string").Parse(templ))
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			var buf bytes.Buffer
-			if err := tpl.Execute(&buf, tt.in); err != nil {
-				t.Fatalf("Cannot render template: %v", err)
-			}
-			trimmed := bytes.TrimSuffix(bytes.TrimPrefix(buf.Bytes(), []byte(prefix)), []byte(suffix))
-			var got string
-			if err := json.Unmarshal(trimmed, &got); err != nil {
-				t.Fatalf("Cannot parse JS string %q as JSON: %v", trimmed[1:len(trimmed)-1], err)
-			}
-			if got != tt.in {
-				t.Errorf("Serialization changed the string value: got %q want %q", got, tt.in)
-			}
-		})
-	}
-}
-
-func TestSkipEscapeComments(t *testing.T) {
-	c := newTestCase(t)
-	tr := parse.New("root")
-	tr.Mode = parse.ParseComments
-	newT, err := tr.Parse("{{/* A comment */}}{{ 1 }}{{/* Another comment */}}", "", "", make(map[string]*parse.Tree))
-	if err != nil {
-		t.Fatalf("Cannot parse template text: %v", err)
-	}
-	c.root, err = c.root.AddParseTree("root", newT)
-	if err != nil {
-		t.Fatalf("Cannot add parse tree to template: %v", err)
-	}
-	c.mustExecute(c.root, nil, "1")
-}
-
-type testCase struct {
-	t    *testing.T
-	root *Template
-}
-
-func newTestCase(t *testing.T) *testCase {
-	return &testCase{
-		t:    t,
-		root: New("root"),
-	}
-}
-
-func (c *testCase) lookup(name string) *Template {
-	return c.root.Lookup(name)
-}
-
-func (c *testCase) mustParse(t *Template, text string) {
-	_, err := t.Parse(text)
-	if err != nil {
-		c.t.Fatalf("parse: %v", err)
-	}
-}
-
-func (c *testCase) mustNotParse(t *Template, text string) {
-	_, err := t.Parse(text)
-	if err == nil {
-		c.t.Fatalf("parse: unexpected success")
-	}
-}
-
-func (c *testCase) mustExecute(t *Template, val interface{}, want string) {
-	var buf bytes.Buffer
-	err := t.Execute(&buf, val)
-	if err != nil {
-		c.t.Fatalf("execute: %v", err)
-	}
-	if buf.String() != want {
-		c.t.Fatalf("template output:\n%s\nwant:\n%s", buf.String(), want)
-	}
-}
diff --git a/go.dev/cmd/internal/html/template/testdata/file1.tmpl b/go.dev/cmd/internal/html/template/testdata/file1.tmpl
deleted file mode 100644
index febf9d9..0000000
--- a/go.dev/cmd/internal/html/template/testdata/file1.tmpl
+++ /dev/null
@@ -1,2 +0,0 @@
-{{define "x"}}TEXT{{end}}
-{{define "dotV"}}{{.V}}{{end}}
diff --git a/go.dev/cmd/internal/html/template/testdata/file2.tmpl b/go.dev/cmd/internal/html/template/testdata/file2.tmpl
deleted file mode 100644
index 39bf6fb..0000000
--- a/go.dev/cmd/internal/html/template/testdata/file2.tmpl
+++ /dev/null
@@ -1,2 +0,0 @@
-{{define "dot"}}{{.}}{{end}}
-{{define "nested"}}{{template "dot" .}}{{end}}
diff --git a/go.dev/cmd/internal/html/template/testdata/fs.zip b/go.dev/cmd/internal/html/template/testdata/fs.zip
deleted file mode 100644
index 8581313..0000000
--- a/go.dev/cmd/internal/html/template/testdata/fs.zip
+++ /dev/null
Binary files differ
diff --git a/go.dev/cmd/internal/html/template/testdata/tmpl1.tmpl b/go.dev/cmd/internal/html/template/testdata/tmpl1.tmpl
deleted file mode 100644
index b72b3a3..0000000
--- a/go.dev/cmd/internal/html/template/testdata/tmpl1.tmpl
+++ /dev/null
@@ -1,3 +0,0 @@
-template1
-{{define "x"}}x{{end}}
-{{template "y"}}
diff --git a/go.dev/cmd/internal/html/template/testdata/tmpl2.tmpl b/go.dev/cmd/internal/html/template/testdata/tmpl2.tmpl
deleted file mode 100644
index 16beba6..0000000
--- a/go.dev/cmd/internal/html/template/testdata/tmpl2.tmpl
+++ /dev/null
@@ -1,3 +0,0 @@
-template2
-{{define "y"}}y{{end}}
-{{template "x"}}
diff --git a/go.dev/cmd/internal/html/template/transition.go b/go.dev/cmd/internal/html/template/transition.go
deleted file mode 100644
index 06df679..0000000
--- a/go.dev/cmd/internal/html/template/transition.go
+++ /dev/null
@@ -1,592 +0,0 @@
-// Copyright 2011 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 template
-
-import (
-	"bytes"
-	"strings"
-)
-
-// transitionFunc is the array of context transition functions for text nodes.
-// A transition function takes a context and template text input, and returns
-// the updated context and the number of bytes consumed from the front of the
-// input.
-var transitionFunc = [...]func(context, []byte) (context, int){
-	stateText:        tText,
-	stateTag:         tTag,
-	stateAttrName:    tAttrName,
-	stateAfterName:   tAfterName,
-	stateBeforeValue: tBeforeValue,
-	stateHTMLCmt:     tHTMLCmt,
-	stateRCDATA:      tSpecialTagEnd,
-	stateAttr:        tAttr,
-	stateURL:         tURL,
-	stateSrcset:      tURL,
-	stateJS:          tJS,
-	stateJSDqStr:     tJSDelimited,
-	stateJSSqStr:     tJSDelimited,
-	stateJSRegexp:    tJSDelimited,
-	stateJSBlockCmt:  tBlockCmt,
-	stateJSLineCmt:   tLineCmt,
-	stateCSS:         tCSS,
-	stateCSSDqStr:    tCSSStr,
-	stateCSSSqStr:    tCSSStr,
-	stateCSSDqURL:    tCSSStr,
-	stateCSSSqURL:    tCSSStr,
-	stateCSSURL:      tCSSStr,
-	stateCSSBlockCmt: tBlockCmt,
-	stateCSSLineCmt:  tLineCmt,
-	stateError:       tError,
-}
-
-var commentStart = []byte("<!--")
-var commentEnd = []byte("-->")
-
-// tText is the context transition function for the text state.
-func tText(c context, s []byte) (context, int) {
-	k := 0
-	for {
-		i := k + bytes.IndexByte(s[k:], '<')
-		if i < k || i+1 == len(s) {
-			return c, len(s)
-		} else if i+4 <= len(s) && bytes.Equal(commentStart, s[i:i+4]) {
-			return context{state: stateHTMLCmt}, i + 4
-		}
-		i++
-		end := false
-		if s[i] == '/' {
-			if i+1 == len(s) {
-				return c, len(s)
-			}
-			end, i = true, i+1
-		}
-		j, e := eatTagName(s, i)
-		if j != i {
-			if end {
-				e = elementNone
-			}
-			// We've found an HTML tag.
-			return context{state: stateTag, element: e}, j
-		}
-		k = j
-	}
-}
-
-var elementContentType = [...]state{
-	elementNone:     stateText,
-	elementScript:   stateJS,
-	elementStyle:    stateCSS,
-	elementTextarea: stateRCDATA,
-	elementTitle:    stateRCDATA,
-}
-
-// tTag is the context transition function for the tag state.
-func tTag(c context, s []byte) (context, int) {
-	// Find the attribute name.
-	i := eatWhiteSpace(s, 0)
-	if i == len(s) {
-		return c, len(s)
-	}
-	if s[i] == '>' {
-		return context{
-			state:   elementContentType[c.element],
-			element: c.element,
-		}, i + 1
-	}
-	j, err := eatAttrName(s, i)
-	if err != nil {
-		return context{state: stateError, err: err}, len(s)
-	}
-	state, attr := stateTag, attrNone
-	if i == j {
-		return context{
-			state: stateError,
-			err:   errorf(ErrBadHTML, nil, 0, "expected space, attr name, or end of tag, but got %q", s[i:]),
-		}, len(s)
-	}
-
-	attrName := strings.ToLower(string(s[i:j]))
-	if c.element == elementScript && attrName == "type" {
-		attr = attrScriptType
-	} else {
-		switch attrType(attrName) {
-		case contentTypeURL:
-			attr = attrURL
-		case contentTypeCSS:
-			attr = attrStyle
-		case contentTypeJS:
-			attr = attrScript
-		case contentTypeSrcset:
-			attr = attrSrcset
-		}
-	}
-
-	if j == len(s) {
-		state = stateAttrName
-	} else {
-		state = stateAfterName
-	}
-	return context{state: state, element: c.element, attr: attr}, j
-}
-
-// tAttrName is the context transition function for stateAttrName.
-func tAttrName(c context, s []byte) (context, int) {
-	i, err := eatAttrName(s, 0)
-	if err != nil {
-		return context{state: stateError, err: err}, len(s)
-	} else if i != len(s) {
-		c.state = stateAfterName
-	}
-	return c, i
-}
-
-// tAfterName is the context transition function for stateAfterName.
-func tAfterName(c context, s []byte) (context, int) {
-	// Look for the start of the value.
-	i := eatWhiteSpace(s, 0)
-	if i == len(s) {
-		return c, len(s)
-	} else if s[i] != '=' {
-		// Occurs due to tag ending '>', and valueless attribute.
-		c.state = stateTag
-		return c, i
-	}
-	c.state = stateBeforeValue
-	// Consume the "=".
-	return c, i + 1
-}
-
-var attrStartStates = [...]state{
-	attrNone:       stateAttr,
-	attrScript:     stateJS,
-	attrScriptType: stateAttr,
-	attrStyle:      stateCSS,
-	attrURL:        stateURL,
-	attrSrcset:     stateSrcset,
-}
-
-// tBeforeValue is the context transition function for stateBeforeValue.
-func tBeforeValue(c context, s []byte) (context, int) {
-	i := eatWhiteSpace(s, 0)
-	if i == len(s) {
-		return c, len(s)
-	}
-	// Find the attribute delimiter.
-	delim := delimSpaceOrTagEnd
-	switch s[i] {
-	case '\'':
-		delim, i = delimSingleQuote, i+1
-	case '"':
-		delim, i = delimDoubleQuote, i+1
-	}
-	c.state, c.delim = attrStartStates[c.attr], delim
-	return c, i
-}
-
-// tHTMLCmt is the context transition function for stateHTMLCmt.
-func tHTMLCmt(c context, s []byte) (context, int) {
-	if i := bytes.Index(s, commentEnd); i != -1 {
-		return context{}, i + 3
-	}
-	return c, len(s)
-}
-
-// specialTagEndMarkers maps element types to the character sequence that
-// case-insensitively signals the end of the special tag body.
-var specialTagEndMarkers = [...][]byte{
-	elementScript:   []byte("script"),
-	elementStyle:    []byte("style"),
-	elementTextarea: []byte("textarea"),
-	elementTitle:    []byte("title"),
-}
-
-var (
-	specialTagEndPrefix = []byte("</")
-	tagEndSeparators    = []byte("> \t\n\f/")
-)
-
-// tSpecialTagEnd is the context transition function for raw text and RCDATA
-// element states.
-func tSpecialTagEnd(c context, s []byte) (context, int) {
-	if c.element != elementNone {
-		if i := indexTagEnd(s, specialTagEndMarkers[c.element]); i != -1 {
-			return context{}, i
-		}
-	}
-	return c, len(s)
-}
-
-// indexTagEnd finds the index of a special tag end in a case insensitive way, or returns -1
-func indexTagEnd(s []byte, tag []byte) int {
-	res := 0
-	plen := len(specialTagEndPrefix)
-	for len(s) > 0 {
-		// Try to find the tag end prefix first
-		i := bytes.Index(s, specialTagEndPrefix)
-		if i == -1 {
-			return i
-		}
-		s = s[i+plen:]
-		// Try to match the actual tag if there is still space for it
-		if len(tag) <= len(s) && bytes.EqualFold(tag, s[:len(tag)]) {
-			s = s[len(tag):]
-			// Check the tag is followed by a proper separator
-			if len(s) > 0 && bytes.IndexByte(tagEndSeparators, s[0]) != -1 {
-				return res + i
-			}
-			res += len(tag)
-		}
-		res += i + plen
-	}
-	return -1
-}
-
-// tAttr is the context transition function for the attribute state.
-func tAttr(c context, s []byte) (context, int) {
-	return c, len(s)
-}
-
-// tURL is the context transition function for the URL state.
-func tURL(c context, s []byte) (context, int) {
-	if bytes.ContainsAny(s, "#?") {
-		c.urlPart = urlPartQueryOrFrag
-	} else if len(s) != eatWhiteSpace(s, 0) && c.urlPart == urlPartNone {
-		// HTML5 uses "Valid URL potentially surrounded by spaces" for
-		// attrs: https://www.w3.org/TR/html5/index.html#attributes-1
-		c.urlPart = urlPartPreQuery
-	}
-	return c, len(s)
-}
-
-// tJS is the context transition function for the JS state.
-func tJS(c context, s []byte) (context, int) {
-	i := bytes.IndexAny(s, `"'/`)
-	if i == -1 {
-		// Entire input is non string, comment, regexp tokens.
-		c.jsCtx = nextJSCtx(s, c.jsCtx)
-		return c, len(s)
-	}
-	c.jsCtx = nextJSCtx(s[:i], c.jsCtx)
-	switch s[i] {
-	case '"':
-		c.state, c.jsCtx = stateJSDqStr, jsCtxRegexp
-	case '\'':
-		c.state, c.jsCtx = stateJSSqStr, jsCtxRegexp
-	case '/':
-		switch {
-		case i+1 < len(s) && s[i+1] == '/':
-			c.state, i = stateJSLineCmt, i+1
-		case i+1 < len(s) && s[i+1] == '*':
-			c.state, i = stateJSBlockCmt, i+1
-		case c.jsCtx == jsCtxRegexp:
-			c.state = stateJSRegexp
-		case c.jsCtx == jsCtxDivOp:
-			c.jsCtx = jsCtxRegexp
-		default:
-			return context{
-				state: stateError,
-				err:   errorf(ErrSlashAmbig, nil, 0, "'/' could start a division or regexp: %.32q", s[i:]),
-			}, len(s)
-		}
-	default:
-		panic("unreachable")
-	}
-	return c, i + 1
-}
-
-// tJSDelimited is the context transition function for the JS string and regexp
-// states.
-func tJSDelimited(c context, s []byte) (context, int) {
-	specials := `\"`
-	switch c.state {
-	case stateJSSqStr:
-		specials = `\'`
-	case stateJSRegexp:
-		specials = `\/[]`
-	}
-
-	k, inCharset := 0, false
-	for {
-		i := k + bytes.IndexAny(s[k:], specials)
-		if i < k {
-			break
-		}
-		switch s[i] {
-		case '\\':
-			i++
-			if i == len(s) {
-				return context{
-					state: stateError,
-					err:   errorf(ErrPartialEscape, nil, 0, "unfinished escape sequence in JS string: %q", s),
-				}, len(s)
-			}
-		case '[':
-			inCharset = true
-		case ']':
-			inCharset = false
-		default:
-			// end delimiter
-			if !inCharset {
-				c.state, c.jsCtx = stateJS, jsCtxDivOp
-				return c, i + 1
-			}
-		}
-		k = i + 1
-	}
-
-	if inCharset {
-		// This can be fixed by making context richer if interpolation
-		// into charsets is desired.
-		return context{
-			state: stateError,
-			err:   errorf(ErrPartialCharset, nil, 0, "unfinished JS regexp charset: %q", s),
-		}, len(s)
-	}
-
-	return c, len(s)
-}
-
-var blockCommentEnd = []byte("*/")
-
-// tBlockCmt is the context transition function for /*comment*/ states.
-func tBlockCmt(c context, s []byte) (context, int) {
-	i := bytes.Index(s, blockCommentEnd)
-	if i == -1 {
-		return c, len(s)
-	}
-	switch c.state {
-	case stateJSBlockCmt:
-		c.state = stateJS
-	case stateCSSBlockCmt:
-		c.state = stateCSS
-	default:
-		panic(c.state.String())
-	}
-	return c, i + 2
-}
-
-// tLineCmt is the context transition function for //comment states.
-func tLineCmt(c context, s []byte) (context, int) {
-	var lineTerminators string
-	var endState state
-	switch c.state {
-	case stateJSLineCmt:
-		lineTerminators, endState = "\n\r\u2028\u2029", stateJS
-	case stateCSSLineCmt:
-		lineTerminators, endState = "\n\f\r", stateCSS
-		// Line comments are not part of any published CSS standard but
-		// are supported by the 4 major browsers.
-		// This defines line comments as
-		//     LINECOMMENT ::= "//" [^\n\f\d]*
-		// since https://www.w3.org/TR/css3-syntax/#SUBTOK-nl defines
-		// newlines:
-		//     nl ::= #xA | #xD #xA | #xD | #xC
-	default:
-		panic(c.state.String())
-	}
-
-	i := bytes.IndexAny(s, lineTerminators)
-	if i == -1 {
-		return c, len(s)
-	}
-	c.state = endState
-	// Per section 7.4 of EcmaScript 5 : https://es5.github.com/#x7.4
-	// "However, the LineTerminator at the end of the line is not
-	// considered to be part of the single-line comment; it is
-	// recognized separately by the lexical grammar and becomes part
-	// of the stream of input elements for the syntactic grammar."
-	return c, i
-}
-
-// tCSS is the context transition function for the CSS state.
-func tCSS(c context, s []byte) (context, int) {
-	// CSS quoted strings are almost never used except for:
-	// (1) URLs as in background: "/foo.png"
-	// (2) Multiword font-names as in font-family: "Times New Roman"
-	// (3) List separators in content values as in inline-lists:
-	//    <style>
-	//    ul.inlineList { list-style: none; padding:0 }
-	//    ul.inlineList > li { display: inline }
-	//    ul.inlineList > li:before { content: ", " }
-	//    ul.inlineList > li:first-child:before { content: "" }
-	//    </style>
-	//    <ul class=inlineList><li>One<li>Two<li>Three</ul>
-	// (4) Attribute value selectors as in a[href="http://example.com/"]
-	//
-	// We conservatively treat all strings as URLs, but make some
-	// allowances to avoid confusion.
-	//
-	// In (1), our conservative assumption is justified.
-	// In (2), valid font names do not contain ':', '?', or '#', so our
-	// conservative assumption is fine since we will never transition past
-	// urlPartPreQuery.
-	// In (3), our protocol heuristic should not be tripped, and there
-	// should not be non-space content after a '?' or '#', so as long as
-	// we only %-encode RFC 3986 reserved characters we are ok.
-	// In (4), we should URL escape for URL attributes, and for others we
-	// have the attribute name available if our conservative assumption
-	// proves problematic for real code.
-
-	k := 0
-	for {
-		i := k + bytes.IndexAny(s[k:], `("'/`)
-		if i < k {
-			return c, len(s)
-		}
-		switch s[i] {
-		case '(':
-			// Look for url to the left.
-			p := bytes.TrimRight(s[:i], "\t\n\f\r ")
-			if endsWithCSSKeyword(p, "url") {
-				j := len(s) - len(bytes.TrimLeft(s[i+1:], "\t\n\f\r "))
-				switch {
-				case j != len(s) && s[j] == '"':
-					c.state, j = stateCSSDqURL, j+1
-				case j != len(s) && s[j] == '\'':
-					c.state, j = stateCSSSqURL, j+1
-				default:
-					c.state = stateCSSURL
-				}
-				return c, j
-			}
-		case '/':
-			if i+1 < len(s) {
-				switch s[i+1] {
-				case '/':
-					c.state = stateCSSLineCmt
-					return c, i + 2
-				case '*':
-					c.state = stateCSSBlockCmt
-					return c, i + 2
-				}
-			}
-		case '"':
-			c.state = stateCSSDqStr
-			return c, i + 1
-		case '\'':
-			c.state = stateCSSSqStr
-			return c, i + 1
-		}
-		k = i + 1
-	}
-}
-
-// tCSSStr is the context transition function for the CSS string and URL states.
-func tCSSStr(c context, s []byte) (context, int) {
-	var endAndEsc string
-	switch c.state {
-	case stateCSSDqStr, stateCSSDqURL:
-		endAndEsc = `\"`
-	case stateCSSSqStr, stateCSSSqURL:
-		endAndEsc = `\'`
-	case stateCSSURL:
-		// Unquoted URLs end with a newline or close parenthesis.
-		// The below includes the wc (whitespace character) and nl.
-		endAndEsc = "\\\t\n\f\r )"
-	default:
-		panic(c.state.String())
-	}
-
-	k := 0
-	for {
-		i := k + bytes.IndexAny(s[k:], endAndEsc)
-		if i < k {
-			c, nread := tURL(c, decodeCSS(s[k:]))
-			return c, k + nread
-		}
-		if s[i] == '\\' {
-			i++
-			if i == len(s) {
-				return context{
-					state: stateError,
-					err:   errorf(ErrPartialEscape, nil, 0, "unfinished escape sequence in CSS string: %q", s),
-				}, len(s)
-			}
-		} else {
-			c.state = stateCSS
-			return c, i + 1
-		}
-		c, _ = tURL(c, decodeCSS(s[:i+1]))
-		k = i + 1
-	}
-}
-
-// tError is the context transition function for the error state.
-func tError(c context, s []byte) (context, int) {
-	return c, len(s)
-}
-
-// eatAttrName returns the largest j such that s[i:j] is an attribute name.
-// It returns an error if s[i:] does not look like it begins with an
-// attribute name, such as encountering a quote mark without a preceding
-// equals sign.
-func eatAttrName(s []byte, i int) (int, *Error) {
-	for j := i; j < len(s); j++ {
-		switch s[j] {
-		case ' ', '\t', '\n', '\f', '\r', '=', '>':
-			return j, nil
-		case '\'', '"', '<':
-			// These result in a parse warning in HTML5 and are
-			// indicative of serious problems if seen in an attr
-			// name in a template.
-			return -1, errorf(ErrBadHTML, nil, 0, "%q in attribute name: %.32q", s[j:j+1], s)
-		default:
-			// No-op.
-		}
-	}
-	return len(s), nil
-}
-
-var elementNameMap = map[string]element{
-	"script":   elementScript,
-	"style":    elementStyle,
-	"textarea": elementTextarea,
-	"title":    elementTitle,
-}
-
-// asciiAlpha reports whether c is an ASCII letter.
-func asciiAlpha(c byte) bool {
-	return 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z'
-}
-
-// asciiAlphaNum reports whether c is an ASCII letter or digit.
-func asciiAlphaNum(c byte) bool {
-	return asciiAlpha(c) || '0' <= c && c <= '9'
-}
-
-// eatTagName returns the largest j such that s[i:j] is a tag name and the tag type.
-func eatTagName(s []byte, i int) (int, element) {
-	if i == len(s) || !asciiAlpha(s[i]) {
-		return i, elementNone
-	}
-	j := i + 1
-	for j < len(s) {
-		x := s[j]
-		if asciiAlphaNum(x) {
-			j++
-			continue
-		}
-		// Allow "x-y" or "x:y" but not "x-", "-y", or "x--y".
-		if (x == ':' || x == '-') && j+1 < len(s) && asciiAlphaNum(s[j+1]) {
-			j += 2
-			continue
-		}
-		break
-	}
-	return j, elementNameMap[strings.ToLower(string(s[i:j]))]
-}
-
-// eatWhiteSpace returns the largest j such that s[i:j] is white space.
-func eatWhiteSpace(s []byte, i int) int {
-	for j := i; j < len(s); j++ {
-		switch s[j] {
-		case ' ', '\t', '\n', '\f', '\r':
-			// No-op.
-		default:
-			return j
-		}
-	}
-	return len(s)
-}
diff --git a/go.dev/cmd/internal/html/template/transition_test.go b/go.dev/cmd/internal/html/template/transition_test.go
deleted file mode 100644
index 412a4c7..0000000
--- a/go.dev/cmd/internal/html/template/transition_test.go
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright 2011 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 template
-
-import (
-	"bytes"
-	"strings"
-	"testing"
-)
-
-func TestFindEndTag(t *testing.T) {
-	tests := []struct {
-		s, tag string
-		want   int
-	}{
-		{"", "tag", -1},
-		{"hello </textarea> hello", "textarea", 6},
-		{"hello </TEXTarea> hello", "textarea", 6},
-		{"hello </textAREA>", "textarea", 6},
-		{"hello </textarea", "textareax", -1},
-		{"hello </textarea>", "tag", -1},
-		{"hello tag </textarea", "tag", -1},
-		{"hello </tag> </other> </textarea> <other>", "textarea", 22},
-		{"</textarea> <other>", "textarea", 0},
-		{"<div> </div> </TEXTAREA>", "textarea", 13},
-		{"<div> </div> </TEXTAREA\t>", "textarea", 13},
-		{"<div> </div> </TEXTAREA >", "textarea", 13},
-		{"<div> </div> </TEXTAREAfoo", "textarea", -1},
-		{"</TEXTAREAfoo </textarea>", "textarea", 14},
-		{"<</script >", "script", 1},
-		{"</script>", "textarea", -1},
-	}
-	for _, test := range tests {
-		if got := indexTagEnd([]byte(test.s), []byte(test.tag)); test.want != got {
-			t.Errorf("%q/%q: want\n\t%d\nbut got\n\t%d", test.s, test.tag, test.want, got)
-		}
-	}
-}
-
-func BenchmarkTemplateSpecialTags(b *testing.B) {
-
-	r := struct {
-		Name, Gift string
-	}{"Aunt Mildred", "bone china tea set"}
-
-	h1 := "<textarea> Hello Hello Hello </textarea> "
-	h2 := "<textarea> <p> Dear {{.Name}},\n{{with .Gift}}Thank you for the lovely {{.}}. {{end}}\nBest wishes. </p>\n</textarea>"
-	html := strings.Repeat(h1, 100) + h2 + strings.Repeat(h1, 100) + h2
-
-	var buf bytes.Buffer
-	for i := 0; i < b.N; i++ {
-		tmpl := Must(New("foo").Parse(html))
-		if err := tmpl.Execute(&buf, r); err != nil {
-			b.Fatal(err)
-		}
-		buf.Reset()
-	}
-}
diff --git a/go.dev/cmd/internal/html/template/url.go b/go.dev/cmd/internal/html/template/url.go
deleted file mode 100644
index 6f8185a..0000000
--- a/go.dev/cmd/internal/html/template/url.go
+++ /dev/null
@@ -1,219 +0,0 @@
-// Copyright 2011 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 template
-
-import (
-	"bytes"
-	"fmt"
-	"strings"
-)
-
-// urlFilter returns its input unless it contains an unsafe scheme in which
-// case it defangs the entire URL.
-//
-// Schemes that cause unintended side effects that are irreversible without user
-// interaction are considered unsafe. For example, clicking on a "javascript:"
-// link can immediately trigger JavaScript code execution.
-//
-// This filter conservatively assumes that all schemes other than the following
-// are unsafe:
-//    * http:   Navigates to a new website, and may open a new window or tab.
-//              These side effects can be reversed by navigating back to the
-//              previous website, or closing the window or tab. No irreversible
-//              changes will take place without further user interaction with
-//              the new website.
-//    * https:  Same as http.
-//    * mailto: Opens an email program and starts a new draft. This side effect
-//              is not irreversible until the user explicitly clicks send; it
-//              can be undone by closing the email program.
-//
-// To allow URLs containing other schemes to bypass this filter, developers must
-// explicitly indicate that such a URL is expected and safe by encapsulating it
-// in a template.URL value.
-func urlFilter(args ...interface{}) string {
-	s, t := stringify(args...)
-	if t == contentTypeURL {
-		return s
-	}
-	if !isSafeURL(s) {
-		return "#" + filterFailsafe
-	}
-	return s
-}
-
-// isSafeURL is true if s is a relative URL or if URL has a protocol in
-// (http, https, mailto).
-func isSafeURL(s string) bool {
-	if i := strings.IndexRune(s, ':'); i >= 0 && !strings.ContainsRune(s[:i], '/') {
-
-		protocol := s[:i]
-		if !strings.EqualFold(protocol, "http") && !strings.EqualFold(protocol, "https") && !strings.EqualFold(protocol, "mailto") {
-			return false
-		}
-	}
-	return true
-}
-
-// urlEscaper produces an output that can be embedded in a URL query.
-// The output can be embedded in an HTML attribute without further escaping.
-func urlEscaper(args ...interface{}) string {
-	return urlProcessor(false, args...)
-}
-
-// urlNormalizer normalizes URL content so it can be embedded in a quote-delimited
-// string or parenthesis delimited url(...).
-// The normalizer does not encode all HTML specials. Specifically, it does not
-// encode '&' so correct embedding in an HTML attribute requires escaping of
-// '&' to '&amp;'.
-func urlNormalizer(args ...interface{}) string {
-	return urlProcessor(true, args...)
-}
-
-// urlProcessor normalizes (when norm is true) or escapes its input to produce
-// a valid hierarchical or opaque URL part.
-func urlProcessor(norm bool, args ...interface{}) string {
-	s, t := stringify(args...)
-	if t == contentTypeURL {
-		norm = true
-	}
-	var b bytes.Buffer
-	if processURLOnto(s, norm, &b) {
-		return b.String()
-	}
-	return s
-}
-
-// processURLOnto appends a normalized URL corresponding to its input to b
-// and reports whether the appended content differs from s.
-func processURLOnto(s string, norm bool, b *bytes.Buffer) bool {
-	b.Grow(len(s) + 16)
-	written := 0
-	// The byte loop below assumes that all URLs use UTF-8 as the
-	// content-encoding. This is similar to the URI to IRI encoding scheme
-	// defined in section 3.1 of  RFC 3987, and behaves the same as the
-	// EcmaScript builtin encodeURIComponent.
-	// It should not cause any misencoding of URLs in pages with
-	// Content-type: text/html;charset=UTF-8.
-	for i, n := 0, len(s); i < n; i++ {
-		c := s[i]
-		switch c {
-		// Single quote and parens are sub-delims in RFC 3986, but we
-		// escape them so the output can be embedded in single
-		// quoted attributes and unquoted CSS url(...) constructs.
-		// Single quotes are reserved in URLs, but are only used in
-		// the obsolete "mark" rule in an appendix in RFC 3986
-		// so can be safely encoded.
-		case '!', '#', '$', '&', '*', '+', ',', '/', ':', ';', '=', '?', '@', '[', ']':
-			if norm {
-				continue
-			}
-		// Unreserved according to RFC 3986 sec 2.3
-		// "For consistency, percent-encoded octets in the ranges of
-		// ALPHA (%41-%5A and %61-%7A), DIGIT (%30-%39), hyphen (%2D),
-		// period (%2E), underscore (%5F), or tilde (%7E) should not be
-		// created by URI producers
-		case '-', '.', '_', '~':
-			continue
-		case '%':
-			// When normalizing do not re-encode valid escapes.
-			if norm && i+2 < len(s) && isHex(s[i+1]) && isHex(s[i+2]) {
-				continue
-			}
-		default:
-			// Unreserved according to RFC 3986 sec 2.3
-			if 'a' <= c && c <= 'z' {
-				continue
-			}
-			if 'A' <= c && c <= 'Z' {
-				continue
-			}
-			if '0' <= c && c <= '9' {
-				continue
-			}
-		}
-		b.WriteString(s[written:i])
-		fmt.Fprintf(b, "%%%02x", c)
-		written = i + 1
-	}
-	b.WriteString(s[written:])
-	return written != 0
-}
-
-// Filters and normalizes srcset values which are comma separated
-// URLs followed by metadata.
-func srcsetFilterAndEscaper(args ...interface{}) string {
-	s, t := stringify(args...)
-	switch t {
-	case contentTypeSrcset:
-		return s
-	case contentTypeURL:
-		// Normalizing gets rid of all HTML whitespace
-		// which separate the image URL from its metadata.
-		var b bytes.Buffer
-		if processURLOnto(s, true, &b) {
-			s = b.String()
-		}
-		// Additionally, commas separate one source from another.
-		return strings.ReplaceAll(s, ",", "%2c")
-	}
-
-	var b bytes.Buffer
-	written := 0
-	for i := 0; i < len(s); i++ {
-		if s[i] == ',' {
-			filterSrcsetElement(s, written, i, &b)
-			b.WriteString(",")
-			written = i + 1
-		}
-	}
-	filterSrcsetElement(s, written, len(s), &b)
-	return b.String()
-}
-
-// Derived from https://play.golang.org/p/Dhmj7FORT5
-const htmlSpaceAndASCIIAlnumBytes = "\x00\x36\x00\x00\x01\x00\xff\x03\xfe\xff\xff\x07\xfe\xff\xff\x07"
-
-// isHTMLSpace is true iff c is a whitespace character per
-// https://infra.spec.whatwg.org/#ascii-whitespace
-func isHTMLSpace(c byte) bool {
-	return (c <= 0x20) && 0 != (htmlSpaceAndASCIIAlnumBytes[c>>3]&(1<<uint(c&0x7)))
-}
-
-func isHTMLSpaceOrASCIIAlnum(c byte) bool {
-	return (c < 0x80) && 0 != (htmlSpaceAndASCIIAlnumBytes[c>>3]&(1<<uint(c&0x7)))
-}
-
-func filterSrcsetElement(s string, left int, right int, b *bytes.Buffer) {
-	start := left
-	for start < right && isHTMLSpace(s[start]) {
-		start++
-	}
-	end := right
-	for i := start; i < right; i++ {
-		if isHTMLSpace(s[i]) {
-			end = i
-			break
-		}
-	}
-	if url := s[start:end]; isSafeURL(url) {
-		// If image metadata is only spaces or alnums then
-		// we don't need to URL normalize it.
-		metadataOk := true
-		for i := end; i < right; i++ {
-			if !isHTMLSpaceOrASCIIAlnum(s[i]) {
-				metadataOk = false
-				break
-			}
-		}
-		if metadataOk {
-			b.WriteString(s[left:start])
-			processURLOnto(url, true, b)
-			b.WriteString(s[end:right])
-			return
-		}
-	}
-	b.WriteString("#")
-	b.WriteString(filterFailsafe)
-}
diff --git a/go.dev/cmd/internal/html/template/url_test.go b/go.dev/cmd/internal/html/template/url_test.go
deleted file mode 100644
index 75c354e..0000000
--- a/go.dev/cmd/internal/html/template/url_test.go
+++ /dev/null
@@ -1,169 +0,0 @@
-// Copyright 2011 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 template
-
-import (
-	"testing"
-)
-
-func TestURLNormalizer(t *testing.T) {
-	tests := []struct {
-		url, want string
-	}{
-		{"", ""},
-		{
-			"http://example.com:80/foo/bar?q=foo%20&bar=x+y#frag",
-			"http://example.com:80/foo/bar?q=foo%20&bar=x+y#frag",
-		},
-		{" ", "%20"},
-		{"%7c", "%7c"},
-		{"%7C", "%7C"},
-		{"%2", "%252"},
-		{"%", "%25"},
-		{"%z", "%25z"},
-		{"/foo|bar/%5c\u1234", "/foo%7cbar/%5c%e1%88%b4"},
-	}
-	for _, test := range tests {
-		if got := urlNormalizer(test.url); test.want != got {
-			t.Errorf("%q: want\n\t%q\nbut got\n\t%q", test.url, test.want, got)
-		}
-		if test.want != urlNormalizer(test.want) {
-			t.Errorf("not idempotent: %q", test.want)
-		}
-	}
-}
-
-func TestURLFilters(t *testing.T) {
-	input := ("\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f" +
-		"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" +
-		` !"#$%&'()*+,-./` +
-		`0123456789:;<=>?` +
-		`@ABCDEFGHIJKLMNO` +
-		`PQRSTUVWXYZ[\]^_` +
-		"`abcdefghijklmno" +
-		"pqrstuvwxyz{|}~\x7f" +
-		"\u00A0\u0100\u2028\u2029\ufeff\U0001D11E")
-
-	tests := []struct {
-		name    string
-		escaper func(...interface{}) string
-		escaped string
-	}{
-		{
-			"urlEscaper",
-			urlEscaper,
-			"%00%01%02%03%04%05%06%07%08%09%0a%0b%0c%0d%0e%0f" +
-				"%10%11%12%13%14%15%16%17%18%19%1a%1b%1c%1d%1e%1f" +
-				"%20%21%22%23%24%25%26%27%28%29%2a%2b%2c-.%2f" +
-				"0123456789%3a%3b%3c%3d%3e%3f" +
-				"%40ABCDEFGHIJKLMNO" +
-				"PQRSTUVWXYZ%5b%5c%5d%5e_" +
-				"%60abcdefghijklmno" +
-				"pqrstuvwxyz%7b%7c%7d~%7f" +
-				"%c2%a0%c4%80%e2%80%a8%e2%80%a9%ef%bb%bf%f0%9d%84%9e",
-		},
-		{
-			"urlNormalizer",
-			urlNormalizer,
-			"%00%01%02%03%04%05%06%07%08%09%0a%0b%0c%0d%0e%0f" +
-				"%10%11%12%13%14%15%16%17%18%19%1a%1b%1c%1d%1e%1f" +
-				"%20!%22#$%25&%27%28%29*+,-./" +
-				"0123456789:;%3c=%3e?" +
-				"@ABCDEFGHIJKLMNO" +
-				"PQRSTUVWXYZ[%5c]%5e_" +
-				"%60abcdefghijklmno" +
-				"pqrstuvwxyz%7b%7c%7d~%7f" +
-				"%c2%a0%c4%80%e2%80%a8%e2%80%a9%ef%bb%bf%f0%9d%84%9e",
-		},
-	}
-
-	for _, test := range tests {
-		if s := test.escaper(input); s != test.escaped {
-			t.Errorf("%s: want\n\t%q\ngot\n\t%q", test.name, test.escaped, s)
-			continue
-		}
-	}
-}
-
-func TestSrcsetFilter(t *testing.T) {
-	tests := []struct {
-		name  string
-		input string
-		want  string
-	}{
-		{
-			"one ok",
-			"http://example.com/img.png",
-			"http://example.com/img.png",
-		},
-		{
-			"one ok with metadata",
-			" /img.png 200w",
-			" /img.png 200w",
-		},
-		{
-			"one bad",
-			"javascript:alert(1) 200w",
-			"#ZgotmplZ",
-		},
-		{
-			"two ok",
-			"foo.png, bar.png",
-			"foo.png, bar.png",
-		},
-		{
-			"left bad",
-			"javascript:alert(1), /foo.png",
-			"#ZgotmplZ, /foo.png",
-		},
-		{
-			"right bad",
-			"/bogus#, javascript:alert(1)",
-			"/bogus#,#ZgotmplZ",
-		},
-	}
-
-	for _, test := range tests {
-		if got := srcsetFilterAndEscaper(test.input); got != test.want {
-			t.Errorf("%s: srcsetFilterAndEscaper(%q) want %q != %q", test.name, test.input, test.want, got)
-		}
-	}
-}
-
-func BenchmarkURLEscaper(b *testing.B) {
-	for i := 0; i < b.N; i++ {
-		urlEscaper("http://example.com:80/foo?q=bar%20&baz=x+y#frag")
-	}
-}
-
-func BenchmarkURLEscaperNoSpecials(b *testing.B) {
-	for i := 0; i < b.N; i++ {
-		urlEscaper("TheQuickBrownFoxJumpsOverTheLazyDog.")
-	}
-}
-
-func BenchmarkURLNormalizer(b *testing.B) {
-	for i := 0; i < b.N; i++ {
-		urlNormalizer("The quick brown fox jumps over the lazy dog.\n")
-	}
-}
-
-func BenchmarkURLNormalizerNoSpecials(b *testing.B) {
-	for i := 0; i < b.N; i++ {
-		urlNormalizer("http://example.com:80/foo?q=bar%20&baz=x+y#frag")
-	}
-}
-
-func BenchmarkSrcsetFilter(b *testing.B) {
-	for i := 0; i < b.N; i++ {
-		srcsetFilterAndEscaper(" /foo/bar.png 200w, /baz/boo(1).png")
-	}
-}
-
-func BenchmarkSrcsetFilterNoSpecials(b *testing.B) {
-	for i := 0; i < b.N; i++ {
-		srcsetFilterAndEscaper("http://example.com:80/foo?q=bar%20&baz=x+y#frag")
-	}
-}
diff --git a/go.dev/cmd/internal/html/template/urlpart_string.go b/go.dev/cmd/internal/html/template/urlpart_string.go
deleted file mode 100644
index 813eea9..0000000
--- a/go.dev/cmd/internal/html/template/urlpart_string.go
+++ /dev/null
@@ -1,16 +0,0 @@
-// Code generated by "stringer -type urlPart"; DO NOT EDIT.
-
-package template
-
-import "strconv"
-
-const _urlPart_name = "urlPartNoneurlPartPreQueryurlPartQueryOrFragurlPartUnknown"
-
-var _urlPart_index = [...]uint8{0, 11, 26, 44, 58}
-
-func (i urlPart) String() string {
-	if i >= urlPart(len(_urlPart_index)-1) {
-		return "urlPart(" + strconv.FormatInt(int64(i), 10) + ")"
-	}
-	return _urlPart_name[_urlPart_index[i]:_urlPart_index[i+1]]
-}
diff --git a/go.dev/cmd/internal/site/md.go b/go.dev/cmd/internal/site/md.go
index c36c18c..72e2052 100644
--- a/go.dev/cmd/internal/site/md.go
+++ b/go.dev/cmd/internal/site/md.go
@@ -16,8 +16,8 @@
 	"github.com/yuin/goldmark/renderer/html"
 	"github.com/yuin/goldmark/text"
 	"github.com/yuin/goldmark/util"
-	"golang.org/x/website/go.dev/cmd/internal/html/template"
 	"golang.org/x/website/go.dev/cmd/internal/tmplfunc"
+	"golang.org/x/website/internal/backport/html/template"
 )
 
 // markdownToHTML converts markdown to HTML using the renderer and settings that Hugo uses.
diff --git a/go.dev/cmd/internal/site/site.go b/go.dev/cmd/internal/site/site.go
index f33421c..7ac0a19 100644
--- a/go.dev/cmd/internal/site/site.go
+++ b/go.dev/cmd/internal/site/site.go
@@ -20,7 +20,7 @@
 	"strings"
 	"time"
 
-	"golang.org/x/website/go.dev/cmd/internal/html/template"
+	"golang.org/x/website/internal/backport/html/template"
 	"gopkg.in/yaml.v3"
 )
 
diff --git a/go.dev/cmd/internal/site/tmpl.go b/go.dev/cmd/internal/site/tmpl.go
index a7ad25a..9bf04c1 100644
--- a/go.dev/cmd/internal/site/tmpl.go
+++ b/go.dev/cmd/internal/site/tmpl.go
@@ -9,8 +9,8 @@
 	"reflect"
 	"strings"
 
-	"golang.org/x/website/go.dev/cmd/internal/html/template"
 	"golang.org/x/website/go.dev/cmd/internal/tmplfunc"
+	"golang.org/x/website/internal/backport/html/template"
 	"gopkg.in/yaml.v3"
 )
 
diff --git a/go.dev/cmd/internal/text/template/doc.go b/go.dev/cmd/internal/text/template/doc.go
deleted file mode 100644
index 5332002..0000000
--- a/go.dev/cmd/internal/text/template/doc.go
+++ /dev/null
@@ -1,463 +0,0 @@
-// Copyright 2011 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 template implements data-driven templates for generating textual output.
-
-To generate HTML output, see package html/template, which has the same interface
-as this package but automatically secures HTML output against certain attacks.
-
-Templates are executed by applying them to a data structure. Annotations in the
-template refer to elements of the data structure (typically a field of a struct
-or a key in a map) to control execution and derive values to be displayed.
-Execution of the template walks the structure and sets the cursor, represented
-by a period '.' and called "dot", to the value at the current location in the
-structure as execution proceeds.
-
-The input text for a template is UTF-8-encoded text in any format.
-"Actions"--data evaluations or control structures--are delimited by
-"{{" and "}}"; all text outside actions is copied to the output unchanged.
-Except for raw strings, actions may not span newlines, although comments can.
-
-Once parsed, a template may be executed safely in parallel, although if parallel
-executions share a Writer the output may be interleaved.
-
-Here is a trivial example that prints "17 items are made of wool".
-
-	type Inventory struct {
-		Material string
-		Count    uint
-	}
-	sweaters := Inventory{"wool", 17}
-	tmpl, err := template.New("test").Parse("{{.Count}} items are made of {{.Material}}")
-	if err != nil { panic(err) }
-	err = tmpl.Execute(os.Stdout, sweaters)
-	if err != nil { panic(err) }
-
-More intricate examples appear below.
-
-Text and spaces
-
-By default, all text between actions is copied verbatim when the template is
-executed. For example, the string " items are made of " in the example above
-appears on standard output when the program is run.
-
-However, to aid in formatting template source code, if an action's left
-delimiter (by default "{{") is followed immediately by a minus sign and white
-space, all trailing white space is trimmed from the immediately preceding text.
-Similarly, if the right delimiter ("}}") is preceded by white space and a minus
-sign, all leading white space is trimmed from the immediately following text.
-In these trim markers, the white space must be present:
-"{{- 3}}" is like "{{3}}" but trims the immediately preceding text, while
-"{{-3}}" parses as an action containing the number -3.
-
-For instance, when executing the template whose source is
-
-	"{{23 -}} < {{- 45}}"
-
-the generated output would be
-
-	"23<45"
-
-For this trimming, the definition of white space characters is the same as in Go:
-space, horizontal tab, carriage return, and newline.
-
-Actions
-
-Here is the list of actions. "Arguments" and "pipelines" are evaluations of
-data, defined in detail in the corresponding sections that follow.
-
-*/
-//	{{/* a comment */}}
-//	{{- /* a comment with white space trimmed from preceding and following text */ -}}
-//		A comment; discarded. May contain newlines.
-//		Comments do not nest and must start and end at the
-//		delimiters, as shown here.
-/*
-
-	{{pipeline}}
-		The default textual representation (the same as would be
-		printed by fmt.Print) of the value of the pipeline is copied
-		to the output.
-
-	{{if pipeline}} T1 {{end}}
-		If the value of the pipeline is empty, no output is generated;
-		otherwise, T1 is executed. The empty values are false, 0, any
-		nil pointer or interface value, and any array, slice, map, or
-		string of length zero.
-		Dot is unaffected.
-
-	{{if pipeline}} T1 {{else}} T0 {{end}}
-		If the value of the pipeline is empty, T0 is executed;
-		otherwise, T1 is executed. Dot is unaffected.
-
-	{{if pipeline}} T1 {{else if pipeline}} T0 {{end}}
-		To simplify the appearance of if-else chains, the else action
-		of an if may include another if directly; the effect is exactly
-		the same as writing
-			{{if pipeline}} T1 {{else}}{{if pipeline}} T0 {{end}}{{end}}
-
-	{{range pipeline}} T1 {{end}}
-		The value of the pipeline must be an array, slice, map, or channel.
-		If the value of the pipeline has length zero, nothing is output;
-		otherwise, dot is set to the successive elements of the array,
-		slice, or map and T1 is executed. If the value is a map and the
-		keys are of basic type with a defined order, the elements will be
-		visited in sorted key order.
-
-	{{range pipeline}} T1 {{else}} T0 {{end}}
-		The value of the pipeline must be an array, slice, map, or channel.
-		If the value of the pipeline has length zero, dot is unaffected and
-		T0 is executed; otherwise, dot is set to the successive elements
-		of the array, slice, or map and T1 is executed.
-
-	{{break}}
-		The innermost {{range pipeline}} loop is ended early, stopping the
-		current iteration and bypassing all remaining iterations.
-
-	{{continue}}
-		The current iteration of the innermost {{range pipeline}} loop is
-		stopped, and the loop starts the next iteration.
-
-	{{template "name"}}
-		The template with the specified name is executed with nil data.
-
-	{{template "name" pipeline}}
-		The template with the specified name is executed with dot set
-		to the value of the pipeline.
-
-	{{block "name" pipeline}} T1 {{end}}
-		A block is shorthand for defining a template
-			{{define "name"}} T1 {{end}}
-		and then executing it in place
-			{{template "name" pipeline}}
-		The typical use is to define a set of root templates that are
-		then customized by redefining the block templates within.
-
-	{{with pipeline}} T1 {{end}}
-		If the value of the pipeline is empty, no output is generated;
-		otherwise, dot is set to the value of the pipeline and T1 is
-		executed.
-
-	{{with pipeline}} T1 {{else}} T0 {{end}}
-		If the value of the pipeline is empty, dot is unaffected and T0
-		is executed; otherwise, dot is set to the value of the pipeline
-		and T1 is executed.
-
-Arguments
-
-An argument is a simple value, denoted by one of the following.
-
-	- A boolean, string, character, integer, floating-point, imaginary
-	  or complex constant in Go syntax. These behave like Go's untyped
-	  constants. Note that, as in Go, whether a large integer constant
-	  overflows when assigned or passed to a function can depend on whether
-	  the host machine's ints are 32 or 64 bits.
-	- The keyword nil, representing an untyped Go nil.
-	- The character '.' (period):
-		.
-	  The result is the value of dot.
-	- A variable name, which is a (possibly empty) alphanumeric string
-	  preceded by a dollar sign, such as
-		$piOver2
-	  or
-		$
-	  The result is the value of the variable.
-	  Variables are described below.
-	- The name of a field of the data, which must be a struct, preceded
-	  by a period, such as
-		.Field
-	  The result is the value of the field. Field invocations may be
-	  chained:
-	    .Field1.Field2
-	  Fields can also be evaluated on variables, including chaining:
-	    $x.Field1.Field2
-	- The name of a key of the data, which must be a map, preceded
-	  by a period, such as
-		.Key
-	  The result is the map element value indexed by the key.
-	  Key invocations may be chained and combined with fields to any
-	  depth:
-	    .Field1.Key1.Field2.Key2
-	  Although the key must be an alphanumeric identifier, unlike with
-	  field names they do not need to start with an upper case letter.
-	  Keys can also be evaluated on variables, including chaining:
-	    $x.key1.key2
-	- The name of a niladic method of the data, preceded by a period,
-	  such as
-		.Method
-	  The result is the value of invoking the method with dot as the
-	  receiver, dot.Method(). Such a method must have one return value (of
-	  any type) or two return values, the second of which is an error.
-	  If it has two and the returned error is non-nil, execution terminates
-	  and an error is returned to the caller as the value of Execute.
-	  Method invocations may be chained and combined with fields and keys
-	  to any depth:
-	    .Field1.Key1.Method1.Field2.Key2.Method2
-	  Methods can also be evaluated on variables, including chaining:
-	    $x.Method1.Field
-	- The name of a niladic function, such as
-		fun
-	  The result is the value of invoking the function, fun(). The return
-	  types and values behave as in methods. Functions and function
-	  names are described below.
-	- A parenthesized instance of one the above, for grouping. The result
-	  may be accessed by a field or map key invocation.
-		print (.F1 arg1) (.F2 arg2)
-		(.StructValuedMethod "arg").Field
-
-Arguments may evaluate to any type; if they are pointers the implementation
-automatically indirects to the base type when required.
-If an evaluation yields a function value, such as a function-valued
-field of a struct, the function is not invoked automatically, but it
-can be used as a truth value for an if action and the like. To invoke
-it, use the call function, defined below.
-
-Pipelines
-
-A pipeline is a possibly chained sequence of "commands". A command is a simple
-value (argument) or a function or method call, possibly with multiple arguments:
-
-	Argument
-		The result is the value of evaluating the argument.
-	.Method [Argument...]
-		The method can be alone or the last element of a chain but,
-		unlike methods in the middle of a chain, it can take arguments.
-		The result is the value of calling the method with the
-		arguments:
-			dot.Method(Argument1, etc.)
-	functionName [Argument...]
-		The result is the value of calling the function associated
-		with the name:
-			function(Argument1, etc.)
-		Functions and function names are described below.
-
-A pipeline may be "chained" by separating a sequence of commands with pipeline
-characters '|'. In a chained pipeline, the result of each command is
-passed as the last argument of the following command. The output of the final
-command in the pipeline is the value of the pipeline.
-
-The output of a command will be either one value or two values, the second of
-which has type error. If that second value is present and evaluates to
-non-nil, execution terminates and the error is returned to the caller of
-Execute.
-
-Variables
-
-A pipeline inside an action may initialize a variable to capture the result.
-The initialization has syntax
-
-	$variable := pipeline
-
-where $variable is the name of the variable. An action that declares a
-variable produces no output.
-
-Variables previously declared can also be assigned, using the syntax
-
-	$variable = pipeline
-
-If a "range" action initializes a variable, the variable is set to the
-successive elements of the iteration. Also, a "range" may declare two
-variables, separated by a comma:
-
-	range $index, $element := pipeline
-
-in which case $index and $element are set to the successive values of the
-array/slice index or map key and element, respectively. Note that if there is
-only one variable, it is assigned the element; this is opposite to the
-convention in Go range clauses.
-
-A variable's scope extends to the "end" action of the control structure ("if",
-"with", or "range") in which it is declared, or to the end of the template if
-there is no such control structure. A template invocation does not inherit
-variables from the point of its invocation.
-
-When execution begins, $ is set to the data argument passed to Execute, that is,
-to the starting value of dot.
-
-Examples
-
-Here are some example one-line templates demonstrating pipelines and variables.
-All produce the quoted word "output":
-
-	{{"\"output\""}}
-		A string constant.
-	{{`"output"`}}
-		A raw string constant.
-	{{printf "%q" "output"}}
-		A function call.
-	{{"output" | printf "%q"}}
-		A function call whose final argument comes from the previous
-		command.
-	{{printf "%q" (print "out" "put")}}
-		A parenthesized argument.
-	{{"put" | printf "%s%s" "out" | printf "%q"}}
-		A more elaborate call.
-	{{"output" | printf "%s" | printf "%q"}}
-		A longer chain.
-	{{with "output"}}{{printf "%q" .}}{{end}}
-		A with action using dot.
-	{{with $x := "output" | printf "%q"}}{{$x}}{{end}}
-		A with action that creates and uses a variable.
-	{{with $x := "output"}}{{printf "%q" $x}}{{end}}
-		A with action that uses the variable in another action.
-	{{with $x := "output"}}{{$x | printf "%q"}}{{end}}
-		The same, but pipelined.
-
-Functions
-
-During execution functions are found in two function maps: first in the
-template, then in the global function map. By default, no functions are defined
-in the template but the Funcs method can be used to add them.
-
-Predefined global functions are named as follows.
-
-	and
-		Returns the boolean AND of its arguments by returning the
-		first empty argument or the last argument, that is,
-		"and x y" behaves as "if x then y else x." Only those
-		arguments necessary to determine the answer are evaluated.
-	call
-		Returns the result of calling the first argument, which
-		must be a function, with the remaining arguments as parameters.
-		Thus "call .X.Y 1 2" is, in Go notation, dot.X.Y(1, 2) where
-		Y is a func-valued field, map entry, or the like.
-		The first argument must be the result of an evaluation
-		that yields a value of function type (as distinct from
-		a predefined function such as print). The function must
-		return either one or two result values, the second of which
-		is of type error. If the arguments don't match the function
-		or the returned error value is non-nil, execution stops.
-	html
-		Returns the escaped HTML equivalent of the textual
-		representation of its arguments. This function is unavailable
-		in html/template, with a few exceptions.
-	index
-		Returns the result of indexing its first argument by the
-		following arguments. Thus "index x 1 2 3" is, in Go syntax,
-		x[1][2][3]. Each indexed item must be a map, slice, or array.
-	slice
-		slice returns the result of slicing its first argument by the
-		remaining arguments. Thus "slice x 1 2" is, in Go syntax, x[1:2],
-		while "slice x" is x[:], "slice x 1" is x[1:], and "slice x 1 2 3"
-		is x[1:2:3]. The first argument must be a string, slice, or array.
-	js
-		Returns the escaped JavaScript equivalent of the textual
-		representation of its arguments.
-	len
-		Returns the integer length of its argument.
-	not
-		Returns the boolean negation of its single argument.
-	or
-		Returns the boolean OR of its arguments by returning the
-		first non-empty argument or the last argument, that is,
-		"or x y" behaves as "if x then x else y". Only those
-		arguments necessary to determine the answer are evaluated.
-	print
-		An alias for fmt.Sprint
-	printf
-		An alias for fmt.Sprintf
-	println
-		An alias for fmt.Sprintln
-	urlquery
-		Returns the escaped value of the textual representation of
-		its arguments in a form suitable for embedding in a URL query.
-		This function is unavailable in html/template, with a few
-		exceptions.
-
-The boolean functions take any zero value to be false and a non-zero
-value to be true.
-
-There is also a set of binary comparison operators defined as
-functions:
-
-	eq
-		Returns the boolean truth of arg1 == arg2
-	ne
-		Returns the boolean truth of arg1 != arg2
-	lt
-		Returns the boolean truth of arg1 < arg2
-	le
-		Returns the boolean truth of arg1 <= arg2
-	gt
-		Returns the boolean truth of arg1 > arg2
-	ge
-		Returns the boolean truth of arg1 >= arg2
-
-For simpler multi-way equality tests, eq (only) accepts two or more
-arguments and compares the second and subsequent to the first,
-returning in effect
-
-	arg1==arg2 || arg1==arg3 || arg1==arg4 ...
-
-(Unlike with || in Go, however, eq is a function call and all the
-arguments will be evaluated.)
-
-The comparison functions work on any values whose type Go defines as
-comparable. For basic types such as integers, the rules are relaxed:
-size and exact type are ignored, so any integer value, signed or unsigned,
-may be compared with any other integer value. (The arithmetic value is compared,
-not the bit pattern, so all negative integers are less than all unsigned integers.)
-However, as usual, one may not compare an int with a float32 and so on.
-
-Associated templates
-
-Each template is named by a string specified when it is created. Also, each
-template is associated with zero or more other templates that it may invoke by
-name; such associations are transitive and form a name space of templates.
-
-A template may use a template invocation to instantiate another associated
-template; see the explanation of the "template" action above. The name must be
-that of a template associated with the template that contains the invocation.
-
-Nested template definitions
-
-When parsing a template, another template may be defined and associated with the
-template being parsed. Template definitions must appear at the top level of the
-template, much like global variables in a Go program.
-
-The syntax of such definitions is to surround each template declaration with a
-"define" and "end" action.
-
-The define action names the template being created by providing a string
-constant. Here is a simple example:
-
-	`{{define "T1"}}ONE{{end}}
-	{{define "T2"}}TWO{{end}}
-	{{define "T3"}}{{template "T1"}} {{template "T2"}}{{end}}
-	{{template "T3"}}`
-
-This defines two templates, T1 and T2, and a third T3 that invokes the other two
-when it is executed. Finally it invokes T3. If executed this template will
-produce the text
-
-	ONE TWO
-
-By construction, a template may reside in only one association. If it's
-necessary to have a template addressable from multiple associations, the
-template definition must be parsed multiple times to create distinct *Template
-values, or must be copied with the Clone or AddParseTree method.
-
-Parse may be called multiple times to assemble the various associated templates;
-see the ParseFiles and ParseGlob functions and methods for simple ways to parse
-related templates stored in files.
-
-A template may be executed directly or through ExecuteTemplate, which executes
-an associated template identified by name. To invoke our example above, we
-might write,
-
-	err := tmpl.Execute(os.Stdout, "no data needed")
-	if err != nil {
-		log.Fatalf("execution failed: %s", err)
-	}
-
-or to invoke a particular template explicitly by name,
-
-	err := tmpl.ExecuteTemplate(os.Stdout, "T2", "no data needed")
-	if err != nil {
-		log.Fatalf("execution failed: %s", err)
-	}
-
-*/
-package template
diff --git a/go.dev/cmd/internal/text/template/example_test.go b/go.dev/cmd/internal/text/template/example_test.go
deleted file mode 100644
index 5f2e806..0000000
--- a/go.dev/cmd/internal/text/template/example_test.go
+++ /dev/null
@@ -1,111 +0,0 @@
-// Copyright 2011 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 template_test
-
-import (
-	"log"
-	"os"
-	"strings"
-
-	"golang.org/x/website/go.dev/cmd/internal/text/template"
-)
-
-func ExampleTemplate() {
-	// Define a template.
-	const letter = `
-Dear {{.Name}},
-{{if .Attended}}
-It was a pleasure to see you at the wedding.
-{{- else}}
-It is a shame you couldn't make it to the wedding.
-{{- end}}
-{{with .Gift -}}
-Thank you for the lovely {{.}}.
-{{end}}
-Best wishes,
-Josie
-`
-
-	// Prepare some data to insert into the template.
-	type Recipient struct {
-		Name, Gift string
-		Attended   bool
-	}
-	var recipients = []Recipient{
-		{"Aunt Mildred", "bone china tea set", true},
-		{"Uncle John", "moleskin pants", false},
-		{"Cousin Rodney", "", false},
-	}
-
-	// Create a new template and parse the letter into it.
-	t := template.Must(template.New("letter").Parse(letter))
-
-	// Execute the template for each recipient.
-	for _, r := range recipients {
-		err := t.Execute(os.Stdout, r)
-		if err != nil {
-			log.Println("executing template:", err)
-		}
-	}
-
-	// Output:
-	// Dear Aunt Mildred,
-	//
-	// It was a pleasure to see you at the wedding.
-	// Thank you for the lovely bone china tea set.
-	//
-	// Best wishes,
-	// Josie
-	//
-	// Dear Uncle John,
-	//
-	// It is a shame you couldn't make it to the wedding.
-	// Thank you for the lovely moleskin pants.
-	//
-	// Best wishes,
-	// Josie
-	//
-	// Dear Cousin Rodney,
-	//
-	// It is a shame you couldn't make it to the wedding.
-	//
-	// Best wishes,
-	// Josie
-}
-
-// The following example is duplicated in html/template; keep them in sync.
-
-func ExampleTemplate_block() {
-	const (
-		master  = `Names:{{block "list" .}}{{"\n"}}{{range .}}{{println "-" .}}{{end}}{{end}}`
-		overlay = `{{define "list"}} {{join . ", "}}{{end}} `
-	)
-	var (
-		funcs     = template.FuncMap{"join": strings.Join}
-		guardians = []string{"Gamora", "Groot", "Nebula", "Rocket", "Star-Lord"}
-	)
-	masterTmpl, err := template.New("master").Funcs(funcs).Parse(master)
-	if err != nil {
-		log.Fatal(err)
-	}
-	overlayTmpl, err := template.Must(masterTmpl.Clone()).Parse(overlay)
-	if err != nil {
-		log.Fatal(err)
-	}
-	if err := masterTmpl.Execute(os.Stdout, guardians); err != nil {
-		log.Fatal(err)
-	}
-	if err := overlayTmpl.Execute(os.Stdout, guardians); err != nil {
-		log.Fatal(err)
-	}
-	// Output:
-	// Names:
-	// - Gamora
-	// - Groot
-	// - Nebula
-	// - Rocket
-	// - Star-Lord
-	// Names: Gamora, Groot, Nebula, Rocket, Star-Lord
-}
diff --git a/go.dev/cmd/internal/text/template/examplefiles_test.go b/go.dev/cmd/internal/text/template/examplefiles_test.go
deleted file mode 100644
index b80a9e2..0000000
--- a/go.dev/cmd/internal/text/template/examplefiles_test.go
+++ /dev/null
@@ -1,183 +0,0 @@
-// 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 template_test
-
-import (
-	"io"
-	"io/ioutil"
-	"log"
-	"os"
-	"path/filepath"
-
-	"golang.org/x/website/go.dev/cmd/internal/text/template"
-)
-
-// templateFile defines the contents of a template to be stored in a file, for testing.
-type templateFile struct {
-	name     string
-	contents string
-}
-
-func createTestDir(files []templateFile) string {
-	dir, err := ioutil.TempDir("", "template")
-	if err != nil {
-		log.Fatal(err)
-	}
-	for _, file := range files {
-		f, err := os.Create(filepath.Join(dir, file.name))
-		if err != nil {
-			log.Fatal(err)
-		}
-		defer f.Close()
-		_, err = io.WriteString(f, file.contents)
-		if err != nil {
-			log.Fatal(err)
-		}
-	}
-	return dir
-}
-
-// Here we demonstrate loading a set of templates from a directory.
-func ExampleTemplate_glob() {
-	// Here we create a temporary directory and populate it with our sample
-	// template definition files; usually the template files would already
-	// exist in some location known to the program.
-	dir := createTestDir([]templateFile{
-		// T0.tmpl is a plain template file that just invokes T1.
-		{"T0.tmpl", `T0 invokes T1: ({{template "T1"}})`},
-		// T1.tmpl defines a template, T1 that invokes T2.
-		{"T1.tmpl", `{{define "T1"}}T1 invokes T2: ({{template "T2"}}){{end}}`},
-		// T2.tmpl defines a template T2.
-		{"T2.tmpl", `{{define "T2"}}This is T2{{end}}`},
-	})
-	// Clean up after the test; another quirk of running as an example.
-	defer os.RemoveAll(dir)
-
-	// pattern is the glob pattern used to find all the template files.
-	pattern := filepath.Join(dir, "*.tmpl")
-
-	// Here starts the example proper.
-	// T0.tmpl is the first name matched, so it becomes the starting template,
-	// the value returned by ParseGlob.
-	tmpl := template.Must(template.ParseGlob(pattern))
-
-	err := tmpl.Execute(os.Stdout, nil)
-	if err != nil {
-		log.Fatalf("template execution: %s", err)
-	}
-	// Output:
-	// T0 invokes T1: (T1 invokes T2: (This is T2))
-}
-
-// This example demonstrates one way to share some templates
-// and use them in different contexts. In this variant we add multiple driver
-// templates by hand to an existing bundle of templates.
-func ExampleTemplate_helpers() {
-	// Here we create a temporary directory and populate it with our sample
-	// template definition files; usually the template files would already
-	// exist in some location known to the program.
-	dir := createTestDir([]templateFile{
-		// T1.tmpl defines a template, T1 that invokes T2.
-		{"T1.tmpl", `{{define "T1"}}T1 invokes T2: ({{template "T2"}}){{end}}`},
-		// T2.tmpl defines a template T2.
-		{"T2.tmpl", `{{define "T2"}}This is T2{{end}}`},
-	})
-	// Clean up after the test; another quirk of running as an example.
-	defer os.RemoveAll(dir)
-
-	// pattern is the glob pattern used to find all the template files.
-	pattern := filepath.Join(dir, "*.tmpl")
-
-	// Here starts the example proper.
-	// Load the helpers.
-	templates := template.Must(template.ParseGlob(pattern))
-	// Add one driver template to the bunch; we do this with an explicit template definition.
-	_, err := templates.Parse("{{define `driver1`}}Driver 1 calls T1: ({{template `T1`}})\n{{end}}")
-	if err != nil {
-		log.Fatal("parsing driver1: ", err)
-	}
-	// Add another driver template.
-	_, err = templates.Parse("{{define `driver2`}}Driver 2 calls T2: ({{template `T2`}})\n{{end}}")
-	if err != nil {
-		log.Fatal("parsing driver2: ", err)
-	}
-	// We load all the templates before execution. This package does not require
-	// that behavior but html/template's escaping does, so it's a good habit.
-	err = templates.ExecuteTemplate(os.Stdout, "driver1", nil)
-	if err != nil {
-		log.Fatalf("driver1 execution: %s", err)
-	}
-	err = templates.ExecuteTemplate(os.Stdout, "driver2", nil)
-	if err != nil {
-		log.Fatalf("driver2 execution: %s", err)
-	}
-	// Output:
-	// Driver 1 calls T1: (T1 invokes T2: (This is T2))
-	// Driver 2 calls T2: (This is T2)
-}
-
-// This example demonstrates how to use one group of driver
-// templates with distinct sets of helper templates.
-func ExampleTemplate_share() {
-	// Here we create a temporary directory and populate it with our sample
-	// template definition files; usually the template files would already
-	// exist in some location known to the program.
-	dir := createTestDir([]templateFile{
-		// T0.tmpl is a plain template file that just invokes T1.
-		{"T0.tmpl", "T0 ({{.}} version) invokes T1: ({{template `T1`}})\n"},
-		// T1.tmpl defines a template, T1 that invokes T2. Note T2 is not defined
-		{"T1.tmpl", `{{define "T1"}}T1 invokes T2: ({{template "T2"}}){{end}}`},
-	})
-	// Clean up after the test; another quirk of running as an example.
-	defer os.RemoveAll(dir)
-
-	// pattern is the glob pattern used to find all the template files.
-	pattern := filepath.Join(dir, "*.tmpl")
-
-	// Here starts the example proper.
-	// Load the drivers.
-	drivers := template.Must(template.ParseGlob(pattern))
-
-	// We must define an implementation of the T2 template. First we clone
-	// the drivers, then add a definition of T2 to the template name space.
-
-	// 1. Clone the helper set to create a new name space from which to run them.
-	first, err := drivers.Clone()
-	if err != nil {
-		log.Fatal("cloning helpers: ", err)
-	}
-	// 2. Define T2, version A, and parse it.
-	_, err = first.Parse("{{define `T2`}}T2, version A{{end}}")
-	if err != nil {
-		log.Fatal("parsing T2: ", err)
-	}
-
-	// Now repeat the whole thing, using a different version of T2.
-	// 1. Clone the drivers.
-	second, err := drivers.Clone()
-	if err != nil {
-		log.Fatal("cloning drivers: ", err)
-	}
-	// 2. Define T2, version B, and parse it.
-	_, err = second.Parse("{{define `T2`}}T2, version B{{end}}")
-	if err != nil {
-		log.Fatal("parsing T2: ", err)
-	}
-
-	// Execute the templates in the reverse order to verify the
-	// first is unaffected by the second.
-	err = second.ExecuteTemplate(os.Stdout, "T0.tmpl", "second")
-	if err != nil {
-		log.Fatalf("second execution: %s", err)
-	}
-	err = first.ExecuteTemplate(os.Stdout, "T0.tmpl", "first")
-	if err != nil {
-		log.Fatalf("first: execution: %s", err)
-	}
-
-	// Output:
-	// T0 (second version) invokes T1: (T1 invokes T2: (T2, version B))
-	// T0 (first version) invokes T1: (T1 invokes T2: (T2, version A))
-}
diff --git a/go.dev/cmd/internal/text/template/examplefunc_test.go b/go.dev/cmd/internal/text/template/examplefunc_test.go
deleted file mode 100644
index 826c25c..0000000
--- a/go.dev/cmd/internal/text/template/examplefunc_test.go
+++ /dev/null
@@ -1,55 +0,0 @@
-// 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 template_test
-
-import (
-	"log"
-	"os"
-	"strings"
-
-	"golang.org/x/website/go.dev/cmd/internal/text/template"
-)
-
-// This example demonstrates a custom function to process template text.
-// It installs the strings.Title function and uses it to
-// Make Title Text Look Good In Our Template's Output.
-func ExampleTemplate_func() {
-	// First we create a FuncMap with which to register the function.
-	funcMap := template.FuncMap{
-		// The name "title" is what the function will be called in the template text.
-		"title": strings.Title,
-	}
-
-	// A simple template definition to test our function.
-	// We print the input text several ways:
-	// - the original
-	// - title-cased
-	// - title-cased and then printed with %q
-	// - printed with %q and then title-cased.
-	const templateText = `
-Input: {{printf "%q" .}}
-Output 0: {{title .}}
-Output 1: {{title . | printf "%q"}}
-Output 2: {{printf "%q" . | title}}
-`
-
-	// Create a template, add the function map, and parse the text.
-	tmpl, err := template.New("titleTest").Funcs(funcMap).Parse(templateText)
-	if err != nil {
-		log.Fatalf("parsing: %s", err)
-	}
-
-	// Run the template to verify the output.
-	err = tmpl.Execute(os.Stdout, "the go programming language")
-	if err != nil {
-		log.Fatalf("execution: %s", err)
-	}
-
-	// Output:
-	// Input: "the go programming language"
-	// Output 0: The Go Programming Language
-	// Output 1: "The Go Programming Language"
-	// Output 2: "The Go Programming Language"
-}
diff --git a/go.dev/cmd/internal/text/template/exec.go b/go.dev/cmd/internal/text/template/exec.go
deleted file mode 100644
index be8835a..0000000
--- a/go.dev/cmd/internal/text/template/exec.go
+++ /dev/null
@@ -1,1028 +0,0 @@
-// Copyright 2011 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 template
-
-import (
-	"errors"
-	"fmt"
-	"io"
-	"reflect"
-	"runtime"
-	"strings"
-
-	"golang.org/x/website/go.dev/cmd/internal/fmtsort"
-	"golang.org/x/website/go.dev/cmd/internal/text/template/parse"
-)
-
-// maxExecDepth specifies the maximum stack depth of templates within
-// templates. This limit is only practically reached by accidentally
-// recursive template invocations. This limit allows us to return
-// an error instead of triggering a stack overflow.
-var maxExecDepth = initMaxExecDepth()
-
-func initMaxExecDepth() int {
-	if runtime.GOARCH == "wasm" {
-		return 1000
-	}
-	return 100000
-}
-
-// state represents the state of an execution. It's not part of the
-// template so that multiple executions of the same template
-// can execute in parallel.
-type state struct {
-	tmpl  *Template
-	wr    io.Writer
-	node  parse.Node // current node, for errors
-	vars  []variable // push-down stack of variable values.
-	depth int        // the height of the stack of executing templates.
-}
-
-// variable holds the dynamic value of a variable such as $, $x etc.
-type variable struct {
-	name  string
-	value reflect.Value
-}
-
-// push pushes a new variable on the stack.
-func (s *state) push(name string, value reflect.Value) {
-	s.vars = append(s.vars, variable{name, value})
-}
-
-// mark returns the length of the variable stack.
-func (s *state) mark() int {
-	return len(s.vars)
-}
-
-// pop pops the variable stack up to the mark.
-func (s *state) pop(mark int) {
-	s.vars = s.vars[0:mark]
-}
-
-// setVar overwrites the last declared variable with the given name.
-// Used by variable assignments.
-func (s *state) setVar(name string, value reflect.Value) {
-	for i := s.mark() - 1; i >= 0; i-- {
-		if s.vars[i].name == name {
-			s.vars[i].value = value
-			return
-		}
-	}
-	s.errorf("undefined variable: %s", name)
-}
-
-// setTopVar overwrites the top-nth variable on the stack. Used by range iterations.
-func (s *state) setTopVar(n int, value reflect.Value) {
-	s.vars[len(s.vars)-n].value = value
-}
-
-// varValue returns the value of the named variable.
-func (s *state) varValue(name string) reflect.Value {
-	for i := s.mark() - 1; i >= 0; i-- {
-		if s.vars[i].name == name {
-			return s.vars[i].value
-		}
-	}
-	s.errorf("undefined variable: %s", name)
-	return zero
-}
-
-var zero reflect.Value
-
-type missingValType struct{}
-
-var missingVal = reflect.ValueOf(missingValType{})
-
-// at marks the state to be on node n, for error reporting.
-func (s *state) at(node parse.Node) {
-	s.node = node
-}
-
-// doublePercent returns the string with %'s replaced by %%, if necessary,
-// so it can be used safely inside a Printf format string.
-func doublePercent(str string) string {
-	return strings.ReplaceAll(str, "%", "%%")
-}
-
-// TODO: It would be nice if ExecError was more broken down, but
-// the way ErrorContext embeds the template name makes the
-// processing too clumsy.
-
-// ExecError is the custom error type returned when Execute has an
-// error evaluating its template. (If a write error occurs, the actual
-// error is returned; it will not be of type ExecError.)
-type ExecError struct {
-	Name string // Name of template.
-	Err  error  // Pre-formatted error.
-}
-
-func (e ExecError) Error() string {
-	return e.Err.Error()
-}
-
-func (e ExecError) Unwrap() error {
-	return e.Err
-}
-
-// errorf records an ExecError and terminates processing.
-func (s *state) errorf(format string, args ...interface{}) {
-	name := doublePercent(s.tmpl.Name())
-	if s.node == nil {
-		format = fmt.Sprintf("template: %s: %s", name, format)
-	} else {
-		location, context := s.tmpl.ErrorContext(s.node)
-		format = fmt.Sprintf("template: %s: executing %q at <%s>: %s", location, name, doublePercent(context), format)
-	}
-	panic(ExecError{
-		Name: s.tmpl.Name(),
-		Err:  fmt.Errorf(format, args...),
-	})
-}
-
-// writeError is the wrapper type used internally when Execute has an
-// error writing to its output. We strip the wrapper in errRecover.
-// Note that this is not an implementation of error, so it cannot escape
-// from the package as an error value.
-type writeError struct {
-	Err error // Original error.
-}
-
-func (s *state) writeError(err error) {
-	panic(writeError{
-		Err: err,
-	})
-}
-
-// errRecover is the handler that turns panics into returns from the top
-// level of Parse.
-func errRecover(errp *error) {
-	e := recover()
-	if e != nil {
-		switch err := e.(type) {
-		case runtime.Error:
-			panic(e)
-		case writeError:
-			*errp = err.Err // Strip the wrapper.
-		case ExecError:
-			*errp = err // Keep the wrapper.
-		default:
-			panic(e)
-		}
-	}
-}
-
-// ExecuteTemplate applies the template associated with t that has the given name
-// to the specified data object and writes the output to wr.
-// If an error occurs executing the template or writing its output,
-// execution stops, but partial results may already have been written to
-// the output writer.
-// A template may be executed safely in parallel, although if parallel
-// executions share a Writer the output may be interleaved.
-func (t *Template) ExecuteTemplate(wr io.Writer, name string, data interface{}) error {
-	tmpl := t.Lookup(name)
-	if tmpl == nil {
-		return fmt.Errorf("template: no template %q associated with template %q", name, t.name)
-	}
-	return tmpl.Execute(wr, data)
-}
-
-// Execute applies a parsed template to the specified data object,
-// and writes the output to wr.
-// If an error occurs executing the template or writing its output,
-// execution stops, but partial results may already have been written to
-// the output writer.
-// A template may be executed safely in parallel, although if parallel
-// executions share a Writer the output may be interleaved.
-//
-// If data is a reflect.Value, the template applies to the concrete
-// value that the reflect.Value holds, as in fmt.Print.
-func (t *Template) Execute(wr io.Writer, data interface{}) error {
-	return t.execute(wr, data)
-}
-
-func (t *Template) execute(wr io.Writer, data interface{}) (err error) {
-	defer errRecover(&err)
-	value, ok := data.(reflect.Value)
-	if !ok {
-		value = reflect.ValueOf(data)
-	}
-	state := &state{
-		tmpl: t,
-		wr:   wr,
-		vars: []variable{{"$", value}},
-	}
-	if t.Tree == nil || t.Root == nil {
-		state.errorf("%q is an incomplete or empty template", t.Name())
-	}
-	state.walk(value, t.Root)
-	return
-}
-
-// DefinedTemplates returns a string listing the defined templates,
-// prefixed by the string "; defined templates are: ". If there are none,
-// it returns the empty string. For generating an error message here
-// and in html/template.
-func (t *Template) DefinedTemplates() string {
-	if t.common == nil {
-		return ""
-	}
-	var b strings.Builder
-	t.muTmpl.RLock()
-	defer t.muTmpl.RUnlock()
-	for name, tmpl := range t.tmpl {
-		if tmpl.Tree == nil || tmpl.Root == nil {
-			continue
-		}
-		if b.Len() == 0 {
-			b.WriteString("; defined templates are: ")
-		} else {
-			b.WriteString(", ")
-		}
-		fmt.Fprintf(&b, "%q", name)
-	}
-	return b.String()
-}
-
-// Sentinel errors for use with panic to signal early exits from range loops.
-var (
-	walkBreak    = errors.New("break")
-	walkContinue = errors.New("continue")
-)
-
-// Walk functions step through the major pieces of the template structure,
-// generating output as they go.
-func (s *state) walk(dot reflect.Value, node parse.Node) {
-	s.at(node)
-	switch node := node.(type) {
-	case *parse.ActionNode:
-		// Do not pop variables so they persist until next end.
-		// Also, if the action declares variables, don't print the result.
-		val := s.evalPipeline(dot, node.Pipe)
-		if len(node.Pipe.Decl) == 0 {
-			s.printValue(node, val)
-		}
-	case *parse.BreakNode:
-		panic(walkBreak)
-	case *parse.CommentNode:
-	case *parse.ContinueNode:
-		panic(walkContinue)
-	case *parse.IfNode:
-		s.walkIfOrWith(parse.NodeIf, dot, node.Pipe, node.List, node.ElseList)
-	case *parse.ListNode:
-		for _, node := range node.Nodes {
-			s.walk(dot, node)
-		}
-	case *parse.RangeNode:
-		s.walkRange(dot, node)
-	case *parse.TemplateNode:
-		s.walkTemplate(dot, node)
-	case *parse.TextNode:
-		if _, err := s.wr.Write(node.Text); err != nil {
-			s.writeError(err)
-		}
-	case *parse.WithNode:
-		s.walkIfOrWith(parse.NodeWith, dot, node.Pipe, node.List, node.ElseList)
-	default:
-		s.errorf("unknown node: %s", node)
-	}
-}
-
-// walkIfOrWith walks an 'if' or 'with' node. The two control structures
-// are identical in behavior except that 'with' sets dot.
-func (s *state) walkIfOrWith(typ parse.NodeType, dot reflect.Value, pipe *parse.PipeNode, list, elseList *parse.ListNode) {
-	defer s.pop(s.mark())
-	val := s.evalPipeline(dot, pipe)
-	truth, ok := isTrue(indirectInterface(val))
-	if !ok {
-		s.errorf("if/with can't use %v", val)
-	}
-	if truth {
-		if typ == parse.NodeWith {
-			s.walk(val, list)
-		} else {
-			s.walk(dot, list)
-		}
-	} else if elseList != nil {
-		s.walk(dot, elseList)
-	}
-}
-
-// IsTrue reports whether the value is 'true', in the sense of not the zero of its type,
-// and whether the value has a meaningful truth value. This is the definition of
-// truth used by if and other such actions.
-func IsTrue(val interface{}) (truth, ok bool) {
-	return isTrue(reflect.ValueOf(val))
-}
-
-func isTrue(val reflect.Value) (truth, ok bool) {
-	if !val.IsValid() {
-		// Something like var x interface{}, never set. It's a form of nil.
-		return false, true
-	}
-	switch val.Kind() {
-	case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
-		truth = val.Len() > 0
-	case reflect.Bool:
-		truth = val.Bool()
-	case reflect.Complex64, reflect.Complex128:
-		truth = val.Complex() != 0
-	case reflect.Chan, reflect.Func, reflect.Ptr, reflect.Interface:
-		truth = !val.IsNil()
-	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
-		truth = val.Int() != 0
-	case reflect.Float32, reflect.Float64:
-		truth = val.Float() != 0
-	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
-		truth = val.Uint() != 0
-	case reflect.Struct:
-		truth = true // Struct values are always true.
-	default:
-		return
-	}
-	return truth, true
-}
-
-func (s *state) walkRange(dot reflect.Value, r *parse.RangeNode) {
-	s.at(r)
-	defer func() {
-		if r := recover(); r != nil && r != walkBreak {
-			panic(r)
-		}
-	}()
-	defer s.pop(s.mark())
-	val, _ := indirect(s.evalPipeline(dot, r.Pipe))
-	// mark top of stack before any variables in the body are pushed.
-	mark := s.mark()
-	oneIteration := func(index, elem reflect.Value) {
-		// Set top var (lexically the second if there are two) to the element.
-		if len(r.Pipe.Decl) > 0 {
-			s.setTopVar(1, elem)
-		}
-		// Set next var (lexically the first if there are two) to the index.
-		if len(r.Pipe.Decl) > 1 {
-			s.setTopVar(2, index)
-		}
-		defer s.pop(mark)
-		defer func() {
-			// Consume panic(walkContinue)
-			if r := recover(); r != nil && r != walkContinue {
-				panic(r)
-			}
-		}()
-		s.walk(elem, r.List)
-	}
-	switch val.Kind() {
-	case reflect.Array, reflect.Slice:
-		if val.Len() == 0 {
-			break
-		}
-		for i := 0; i < val.Len(); i++ {
-			oneIteration(reflect.ValueOf(i), val.Index(i))
-		}
-		return
-	case reflect.Map:
-		if val.Len() == 0 {
-			break
-		}
-		om := fmtsort.Sort(val)
-		for i, key := range om.Key {
-			oneIteration(key, om.Value[i])
-		}
-		return
-	case reflect.Chan:
-		if val.IsNil() {
-			break
-		}
-		if val.Type().ChanDir() == reflect.SendDir {
-			s.errorf("range over send-only channel %v", val)
-			break
-		}
-		i := 0
-		for ; ; i++ {
-			elem, ok := val.Recv()
-			if !ok {
-				break
-			}
-			oneIteration(reflect.ValueOf(i), elem)
-		}
-		if i == 0 {
-			break
-		}
-		return
-	case reflect.Invalid:
-		break // An invalid value is likely a nil map, etc. and acts like an empty map.
-	default:
-		s.errorf("range can't iterate over %v", val)
-	}
-	if r.ElseList != nil {
-		s.walk(dot, r.ElseList)
-	}
-}
-
-func (s *state) walkTemplate(dot reflect.Value, t *parse.TemplateNode) {
-	s.at(t)
-	tmpl := s.tmpl.Lookup(t.Name)
-	if tmpl == nil {
-		s.errorf("template %q not defined", t.Name)
-	}
-	if s.depth == maxExecDepth {
-		s.errorf("exceeded maximum template depth (%v)", maxExecDepth)
-	}
-	// Variables declared by the pipeline persist.
-	dot = s.evalPipeline(dot, t.Pipe)
-	newState := *s
-	newState.depth++
-	newState.tmpl = tmpl
-	// No dynamic scoping: template invocations inherit no variables.
-	newState.vars = []variable{{"$", dot}}
-	newState.walk(dot, tmpl.Root)
-}
-
-// Eval functions evaluate pipelines, commands, and their elements and extract
-// values from the data structure by examining fields, calling methods, and so on.
-// The printing of those values happens only through walk functions.
-
-// evalPipeline returns the value acquired by evaluating a pipeline. If the
-// pipeline has a variable declaration, the variable will be pushed on the
-// stack. Callers should therefore pop the stack after they are finished
-// executing commands depending on the pipeline value.
-func (s *state) evalPipeline(dot reflect.Value, pipe *parse.PipeNode) (value reflect.Value) {
-	if pipe == nil {
-		return
-	}
-	s.at(pipe)
-	value = missingVal
-	for _, cmd := range pipe.Cmds {
-		value = s.evalCommand(dot, cmd, value) // previous value is this one's final arg.
-		// If the object has type interface{}, dig down one level to the thing inside.
-		if value.Kind() == reflect.Interface && value.Type().NumMethod() == 0 {
-			value = reflect.ValueOf(value.Interface()) // lovely!
-		}
-	}
-	for _, variable := range pipe.Decl {
-		if pipe.IsAssign {
-			s.setVar(variable.Ident[0], value)
-		} else {
-			s.push(variable.Ident[0], value)
-		}
-	}
-	return value
-}
-
-func (s *state) notAFunction(args []parse.Node, final reflect.Value) {
-	if len(args) > 1 || final != missingVal {
-		s.errorf("can't give argument to non-function %s", args[0])
-	}
-}
-
-func (s *state) evalCommand(dot reflect.Value, cmd *parse.CommandNode, final reflect.Value) reflect.Value {
-	firstWord := cmd.Args[0]
-	switch n := firstWord.(type) {
-	case *parse.FieldNode:
-		return s.evalFieldNode(dot, n, cmd.Args, final)
-	case *parse.ChainNode:
-		return s.evalChainNode(dot, n, cmd.Args, final)
-	case *parse.IdentifierNode:
-		// Must be a function.
-		return s.evalFunction(dot, n, cmd, cmd.Args, final)
-	case *parse.PipeNode:
-		// Parenthesized pipeline. The arguments are all inside the pipeline; final must be absent.
-		s.notAFunction(cmd.Args, final)
-		return s.evalPipeline(dot, n)
-	case *parse.VariableNode:
-		return s.evalVariableNode(dot, n, cmd.Args, final)
-	}
-	s.at(firstWord)
-	s.notAFunction(cmd.Args, final)
-	switch word := firstWord.(type) {
-	case *parse.BoolNode:
-		return reflect.ValueOf(word.True)
-	case *parse.DotNode:
-		return dot
-	case *parse.NilNode:
-		s.errorf("nil is not a command")
-	case *parse.NumberNode:
-		return s.idealConstant(word)
-	case *parse.StringNode:
-		return reflect.ValueOf(word.Text)
-	}
-	s.errorf("can't evaluate command %q", firstWord)
-	panic("not reached")
-}
-
-// idealConstant is called to return the value of a number in a context where
-// we don't know the type. In that case, the syntax of the number tells us
-// its type, and we use Go rules to resolve. Note there is no such thing as
-// a uint ideal constant in this situation - the value must be of int type.
-func (s *state) idealConstant(constant *parse.NumberNode) reflect.Value {
-	// These are ideal constants but we don't know the type
-	// and we have no context.  (If it was a method argument,
-	// we'd know what we need.) The syntax guides us to some extent.
-	s.at(constant)
-	switch {
-	case constant.IsComplex:
-		return reflect.ValueOf(constant.Complex128) // incontrovertible.
-
-	case constant.IsFloat &&
-		!isHexInt(constant.Text) && !isRuneInt(constant.Text) &&
-		strings.ContainsAny(constant.Text, ".eEpP"):
-		return reflect.ValueOf(constant.Float64)
-
-	case constant.IsInt:
-		n := int(constant.Int64)
-		if int64(n) != constant.Int64 {
-			s.errorf("%s overflows int", constant.Text)
-		}
-		return reflect.ValueOf(n)
-
-	case constant.IsUint:
-		s.errorf("%s overflows int", constant.Text)
-	}
-	return zero
-}
-
-func isRuneInt(s string) bool {
-	return len(s) > 0 && s[0] == '\''
-}
-
-func isHexInt(s string) bool {
-	return len(s) > 2 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X') && !strings.ContainsAny(s, "pP")
-}
-
-func (s *state) evalFieldNode(dot reflect.Value, field *parse.FieldNode, args []parse.Node, final reflect.Value) reflect.Value {
-	s.at(field)
-	return s.evalFieldChain(dot, dot, field, field.Ident, args, final)
-}
-
-func (s *state) evalChainNode(dot reflect.Value, chain *parse.ChainNode, args []parse.Node, final reflect.Value) reflect.Value {
-	s.at(chain)
-	if len(chain.Field) == 0 {
-		s.errorf("internal error: no fields in evalChainNode")
-	}
-	if chain.Node.Type() == parse.NodeNil {
-		s.errorf("indirection through explicit nil in %s", chain)
-	}
-	// (pipe).Field1.Field2 has pipe as .Node, fields as .Field. Eval the pipeline, then the fields.
-	pipe := s.evalArg(dot, nil, chain.Node)
-	return s.evalFieldChain(dot, pipe, chain, chain.Field, args, final)
-}
-
-func (s *state) evalVariableNode(dot reflect.Value, variable *parse.VariableNode, args []parse.Node, final reflect.Value) reflect.Value {
-	// $x.Field has $x as the first ident, Field as the second. Eval the var, then the fields.
-	s.at(variable)
-	value := s.varValue(variable.Ident[0])
-	if len(variable.Ident) == 1 {
-		s.notAFunction(args, final)
-		return value
-	}
-	return s.evalFieldChain(dot, value, variable, variable.Ident[1:], args, final)
-}
-
-// evalFieldChain evaluates .X.Y.Z possibly followed by arguments.
-// dot is the environment in which to evaluate arguments, while
-// receiver is the value being walked along the chain.
-func (s *state) evalFieldChain(dot, receiver reflect.Value, node parse.Node, ident []string, args []parse.Node, final reflect.Value) reflect.Value {
-	n := len(ident)
-	for i := 0; i < n-1; i++ {
-		receiver = s.evalField(dot, ident[i], node, nil, missingVal, receiver)
-	}
-	// Now if it's a method, it gets the arguments.
-	return s.evalField(dot, ident[n-1], node, args, final, receiver)
-}
-
-func (s *state) evalFunction(dot reflect.Value, node *parse.IdentifierNode, cmd parse.Node, args []parse.Node, final reflect.Value) reflect.Value {
-	s.at(node)
-	name := node.Ident
-	function, isBuiltin, ok := findFunction(name, s.tmpl)
-	if !ok {
-		s.errorf("%q is not a defined function", name)
-	}
-	return s.evalCall(dot, function, isBuiltin, cmd, name, args, final)
-}
-
-// evalField evaluates an expression like (.Field) or (.Field arg1 arg2).
-// The 'final' argument represents the return value from the preceding
-// value of the pipeline, if any.
-func (s *state) evalField(dot reflect.Value, fieldName string, node parse.Node, args []parse.Node, final, receiver reflect.Value) reflect.Value {
-	if !receiver.IsValid() {
-		if s.tmpl.option.missingKey == mapError { // Treat invalid value as missing map key.
-			s.errorf("nil data; no entry for key %q", fieldName)
-		}
-		return zero
-	}
-	typ := receiver.Type()
-	receiver, isNil := indirect(receiver)
-	if receiver.Kind() == reflect.Interface && isNil {
-		// Calling a method on a nil interface can't work. The
-		// MethodByName method call below would panic.
-		s.errorf("nil pointer evaluating %s.%s", typ, fieldName)
-		return zero
-	}
-
-	// Unless it's an interface, need to get to a value of type *T to guarantee
-	// we see all methods of T and *T.
-	ptr := receiver
-	if ptr.Kind() != reflect.Interface && ptr.Kind() != reflect.Ptr && ptr.CanAddr() {
-		ptr = ptr.Addr()
-	}
-	if method := ptr.MethodByName(fieldName); method.IsValid() {
-		return s.evalCall(dot, method, false, node, fieldName, args, final)
-	}
-	hasArgs := len(args) > 1 || final != missingVal
-	// It's not a method; must be a field of a struct or an element of a map.
-	switch receiver.Kind() {
-	case reflect.Struct:
-		tField, ok := receiver.Type().FieldByName(fieldName)
-		if ok {
-			field := receiver.FieldByIndex(tField.Index)
-			if tField.PkgPath != "" {
-				s.errorf("%s is an unexported field of struct type %s", fieldName, typ)
-			}
-			// If it's a function, we must call it.
-			if hasArgs {
-				s.errorf("%s has arguments but cannot be invoked as function", fieldName)
-			}
-			return field
-		}
-	case reflect.Map:
-		// If it's a map, attempt to use the field name as a key.
-		nameVal := reflect.ValueOf(fieldName)
-		if nameVal.Type().AssignableTo(receiver.Type().Key()) {
-			if hasArgs {
-				s.errorf("%s is not a method but has arguments", fieldName)
-			}
-			result := receiver.MapIndex(nameVal)
-			if !result.IsValid() {
-				switch s.tmpl.option.missingKey {
-				case mapInvalid:
-					// Just use the invalid value.
-				case mapZeroValue:
-					result = reflect.Zero(receiver.Type().Elem())
-				case mapError:
-					s.errorf("map has no entry for key %q", fieldName)
-				}
-			}
-			return result
-		}
-	case reflect.Ptr:
-		etyp := receiver.Type().Elem()
-		if etyp.Kind() == reflect.Struct {
-			if _, ok := etyp.FieldByName(fieldName); !ok {
-				// If there's no such field, say "can't evaluate"
-				// instead of "nil pointer evaluating".
-				break
-			}
-		}
-		if isNil {
-			s.errorf("nil pointer evaluating %s.%s", typ, fieldName)
-		}
-	}
-	s.errorf("can't evaluate field %s in type %s", fieldName, typ)
-	panic("not reached")
-}
-
-var (
-	errorType        = reflect.TypeOf((*error)(nil)).Elem()
-	fmtStringerType  = reflect.TypeOf((*fmt.Stringer)(nil)).Elem()
-	reflectValueType = reflect.TypeOf((*reflect.Value)(nil)).Elem()
-)
-
-// evalCall executes a function or method call. If it's a method, fun already has the receiver bound, so
-// it looks just like a function call. The arg list, if non-nil, includes (in the manner of the shell), arg[0]
-// as the function itself.
-func (s *state) evalCall(dot, fun reflect.Value, isBuiltin bool, node parse.Node, name string, args []parse.Node, final reflect.Value) reflect.Value {
-	if args != nil {
-		args = args[1:] // Zeroth arg is function name/node; not passed to function.
-	}
-	typ := fun.Type()
-	numIn := len(args)
-	if final != missingVal {
-		numIn++
-	}
-	numFixed := len(args)
-	if typ.IsVariadic() {
-		numFixed = typ.NumIn() - 1 // last arg is the variadic one.
-		if numIn < numFixed {
-			s.errorf("wrong number of args for %s: want at least %d got %d", name, typ.NumIn()-1, len(args))
-		}
-	} else if numIn != typ.NumIn() {
-		s.errorf("wrong number of args for %s: want %d got %d", name, typ.NumIn(), numIn)
-	}
-	if !goodFunc(typ) {
-		// TODO: This could still be a confusing error; maybe goodFunc should provide info.
-		s.errorf("can't call method/function %q with %d results", name, typ.NumOut())
-	}
-
-	// Special case for builtin and/or, which short-circuit.
-	if isBuiltin && (name == "and" || name == "or") {
-		argType := typ.In(0)
-		var v reflect.Value
-		for _, arg := range args {
-			v = s.evalArg(dot, argType, arg).Interface().(reflect.Value)
-			if truth(v) == (name == "or") {
-				break
-			}
-		}
-		return v
-	}
-
-	// Build the arg list.
-	argv := make([]reflect.Value, numIn)
-	// Args must be evaluated. Fixed args first.
-	i := 0
-	for ; i < numFixed && i < len(args); i++ {
-		argv[i] = s.evalArg(dot, typ.In(i), args[i])
-	}
-	// Now the ... args.
-	if typ.IsVariadic() {
-		argType := typ.In(typ.NumIn() - 1).Elem() // Argument is a slice.
-		for ; i < len(args); i++ {
-			argv[i] = s.evalArg(dot, argType, args[i])
-		}
-	}
-	// Add final value if necessary.
-	if final != missingVal {
-		t := typ.In(typ.NumIn() - 1)
-		if typ.IsVariadic() {
-			if numIn-1 < numFixed {
-				// The added final argument corresponds to a fixed parameter of the function.
-				// Validate against the type of the actual parameter.
-				t = typ.In(numIn - 1)
-			} else {
-				// The added final argument corresponds to the variadic part.
-				// Validate against the type of the elements of the variadic slice.
-				t = t.Elem()
-			}
-		}
-		argv[i] = s.validateType(final, t)
-	}
-	v, err := safeCall(fun, argv)
-	// If we have an error that is not nil, stop execution and return that
-	// error to the caller.
-	if err != nil {
-		s.at(node)
-		s.errorf("error calling %s: %w", name, err)
-	}
-	if v.Type() == reflectValueType {
-		v = v.Interface().(reflect.Value)
-	}
-	return v
-}
-
-// canBeNil reports whether an untyped nil can be assigned to the type. See reflect.Zero.
-func canBeNil(typ reflect.Type) bool {
-	switch typ.Kind() {
-	case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
-		return true
-	case reflect.Struct:
-		return typ == reflectValueType
-	}
-	return false
-}
-
-// validateType guarantees that the value is valid and assignable to the type.
-func (s *state) validateType(value reflect.Value, typ reflect.Type) reflect.Value {
-	if !value.IsValid() {
-		if typ == nil {
-			// An untyped nil interface{}. Accept as a proper nil value.
-			return reflect.ValueOf(nil)
-		}
-		if canBeNil(typ) {
-			// Like above, but use the zero value of the non-nil type.
-			return reflect.Zero(typ)
-		}
-		s.errorf("invalid value; expected %s", typ)
-	}
-	if typ == reflectValueType && value.Type() != typ {
-		return reflect.ValueOf(value)
-	}
-	if typ != nil && !value.Type().AssignableTo(typ) {
-		if value.Kind() == reflect.Interface && !value.IsNil() {
-			value = value.Elem()
-			if value.Type().AssignableTo(typ) {
-				return value
-			}
-			// fallthrough
-		}
-		// Does one dereference or indirection work? We could do more, as we
-		// do with method receivers, but that gets messy and method receivers
-		// are much more constrained, so it makes more sense there than here.
-		// Besides, one is almost always all you need.
-		switch {
-		case value.Kind() == reflect.Ptr && value.Type().Elem().AssignableTo(typ):
-			value = value.Elem()
-			if !value.IsValid() {
-				s.errorf("dereference of nil pointer of type %s", typ)
-			}
-		case reflect.PtrTo(value.Type()).AssignableTo(typ) && value.CanAddr():
-			value = value.Addr()
-		default:
-			s.errorf("wrong type for value; expected %s; got %s", typ, value.Type())
-		}
-	}
-	return value
-}
-
-func (s *state) evalArg(dot reflect.Value, typ reflect.Type, n parse.Node) reflect.Value {
-	s.at(n)
-	switch arg := n.(type) {
-	case *parse.DotNode:
-		return s.validateType(dot, typ)
-	case *parse.NilNode:
-		if canBeNil(typ) {
-			return reflect.Zero(typ)
-		}
-		s.errorf("cannot assign nil to %s", typ)
-	case *parse.FieldNode:
-		return s.validateType(s.evalFieldNode(dot, arg, []parse.Node{n}, missingVal), typ)
-	case *parse.VariableNode:
-		return s.validateType(s.evalVariableNode(dot, arg, nil, missingVal), typ)
-	case *parse.PipeNode:
-		return s.validateType(s.evalPipeline(dot, arg), typ)
-	case *parse.IdentifierNode:
-		return s.validateType(s.evalFunction(dot, arg, arg, nil, missingVal), typ)
-	case *parse.ChainNode:
-		return s.validateType(s.evalChainNode(dot, arg, nil, missingVal), typ)
-	}
-	switch typ.Kind() {
-	case reflect.Bool:
-		return s.evalBool(typ, n)
-	case reflect.Complex64, reflect.Complex128:
-		return s.evalComplex(typ, n)
-	case reflect.Float32, reflect.Float64:
-		return s.evalFloat(typ, n)
-	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
-		return s.evalInteger(typ, n)
-	case reflect.Interface:
-		if typ.NumMethod() == 0 {
-			return s.evalEmptyInterface(dot, n)
-		}
-	case reflect.Struct:
-		if typ == reflectValueType {
-			return reflect.ValueOf(s.evalEmptyInterface(dot, n))
-		}
-	case reflect.String:
-		return s.evalString(typ, n)
-	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
-		return s.evalUnsignedInteger(typ, n)
-	}
-	s.errorf("can't handle %s for arg of type %s", n, typ)
-	panic("not reached")
-}
-
-func (s *state) evalBool(typ reflect.Type, n parse.Node) reflect.Value {
-	s.at(n)
-	if n, ok := n.(*parse.BoolNode); ok {
-		value := reflect.New(typ).Elem()
-		value.SetBool(n.True)
-		return value
-	}
-	s.errorf("expected bool; found %s", n)
-	panic("not reached")
-}
-
-func (s *state) evalString(typ reflect.Type, n parse.Node) reflect.Value {
-	s.at(n)
-	if n, ok := n.(*parse.StringNode); ok {
-		value := reflect.New(typ).Elem()
-		value.SetString(n.Text)
-		return value
-	}
-	s.errorf("expected string; found %s", n)
-	panic("not reached")
-}
-
-func (s *state) evalInteger(typ reflect.Type, n parse.Node) reflect.Value {
-	s.at(n)
-	if n, ok := n.(*parse.NumberNode); ok && n.IsInt {
-		value := reflect.New(typ).Elem()
-		value.SetInt(n.Int64)
-		return value
-	}
-	s.errorf("expected integer; found %s", n)
-	panic("not reached")
-}
-
-func (s *state) evalUnsignedInteger(typ reflect.Type, n parse.Node) reflect.Value {
-	s.at(n)
-	if n, ok := n.(*parse.NumberNode); ok && n.IsUint {
-		value := reflect.New(typ).Elem()
-		value.SetUint(n.Uint64)
-		return value
-	}
-	s.errorf("expected unsigned integer; found %s", n)
-	panic("not reached")
-}
-
-func (s *state) evalFloat(typ reflect.Type, n parse.Node) reflect.Value {
-	s.at(n)
-	if n, ok := n.(*parse.NumberNode); ok && n.IsFloat {
-		value := reflect.New(typ).Elem()
-		value.SetFloat(n.Float64)
-		return value
-	}
-	s.errorf("expected float; found %s", n)
-	panic("not reached")
-}
-
-func (s *state) evalComplex(typ reflect.Type, n parse.Node) reflect.Value {
-	if n, ok := n.(*parse.NumberNode); ok && n.IsComplex {
-		value := reflect.New(typ).Elem()
-		value.SetComplex(n.Complex128)
-		return value
-	}
-	s.errorf("expected complex; found %s", n)
-	panic("not reached")
-}
-
-func (s *state) evalEmptyInterface(dot reflect.Value, n parse.Node) reflect.Value {
-	s.at(n)
-	switch n := n.(type) {
-	case *parse.BoolNode:
-		return reflect.ValueOf(n.True)
-	case *parse.DotNode:
-		return dot
-	case *parse.FieldNode:
-		return s.evalFieldNode(dot, n, nil, missingVal)
-	case *parse.IdentifierNode:
-		return s.evalFunction(dot, n, n, nil, missingVal)
-	case *parse.NilNode:
-		// NilNode is handled in evalArg, the only place that calls here.
-		s.errorf("evalEmptyInterface: nil (can't happen)")
-	case *parse.NumberNode:
-		return s.idealConstant(n)
-	case *parse.StringNode:
-		return reflect.ValueOf(n.Text)
-	case *parse.VariableNode:
-		return s.evalVariableNode(dot, n, nil, missingVal)
-	case *parse.PipeNode:
-		return s.evalPipeline(dot, n)
-	}
-	s.errorf("can't handle assignment of %s to empty interface argument", n)
-	panic("not reached")
-}
-
-// indirect returns the item at the end of indirection, and a bool to indicate
-// if it's nil. If the returned bool is true, the returned value's kind will be
-// either a pointer or interface.
-func indirect(v reflect.Value) (rv reflect.Value, isNil bool) {
-	for ; v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface; v = v.Elem() {
-		if v.IsNil() {
-			return v, true
-		}
-	}
-	return v, false
-}
-
-// indirectInterface returns the concrete value in an interface value,
-// or else the zero reflect.Value.
-// That is, if v represents the interface value x, the result is the same as reflect.ValueOf(x):
-// the fact that x was an interface value is forgotten.
-func indirectInterface(v reflect.Value) reflect.Value {
-	if v.Kind() != reflect.Interface {
-		return v
-	}
-	if v.IsNil() {
-		return reflect.Value{}
-	}
-	return v.Elem()
-}
-
-// printValue writes the textual representation of the value to the output of
-// the template.
-func (s *state) printValue(n parse.Node, v reflect.Value) {
-	s.at(n)
-	iface, ok := printableValue(v)
-	if !ok {
-		s.errorf("can't print %s of type %s", n, v.Type())
-	}
-	_, err := fmt.Fprint(s.wr, iface)
-	if err != nil {
-		s.writeError(err)
-	}
-}
-
-// printableValue returns the, possibly indirected, interface value inside v that
-// is best for a call to formatted printer.
-func printableValue(v reflect.Value) (interface{}, bool) {
-	if v.Kind() == reflect.Ptr {
-		v, _ = indirect(v) // fmt.Fprint handles nil.
-	}
-	if !v.IsValid() {
-		return "<no value>", true
-	}
-
-	if !v.Type().Implements(errorType) && !v.Type().Implements(fmtStringerType) {
-		if v.CanAddr() && (reflect.PtrTo(v.Type()).Implements(errorType) || reflect.PtrTo(v.Type()).Implements(fmtStringerType)) {
-			v = v.Addr()
-		} else {
-			switch v.Kind() {
-			case reflect.Chan, reflect.Func:
-				return nil, false
-			}
-		}
-	}
-	return v.Interface(), true
-}
diff --git a/go.dev/cmd/internal/text/template/exec_test.go b/go.dev/cmd/internal/text/template/exec_test.go
deleted file mode 100644
index dbf2631..0000000
--- a/go.dev/cmd/internal/text/template/exec_test.go
+++ /dev/null
@@ -1,1782 +0,0 @@
-// Copyright 2011 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 template
-
-import (
-	"bytes"
-	"errors"
-	"flag"
-	"fmt"
-	"io/ioutil"
-	"reflect"
-	"strings"
-	"sync"
-	"testing"
-)
-
-var debug = flag.Bool("debug", false, "show the errors produced by the tests")
-
-// T has lots of interesting pieces to use to test execution.
-type T struct {
-	// Basics
-	True        bool
-	I           int
-	U16         uint16
-	X, S        string
-	FloatZero   float64
-	ComplexZero complex128
-	// Nested structs.
-	U *U
-	// Struct with String method.
-	V0     V
-	V1, V2 *V
-	// Struct with Error method.
-	W0     W
-	W1, W2 *W
-	// Slices
-	SI      []int
-	SICap   []int
-	SIEmpty []int
-	SB      []bool
-	// Arrays
-	AI [3]int
-	// Maps
-	MSI      map[string]int
-	MSIone   map[string]int // one element, for deterministic output
-	MSIEmpty map[string]int
-	MXI      map[interface{}]int
-	MII      map[int]int
-	MI32S    map[int32]string
-	MI64S    map[int64]string
-	MUI32S   map[uint32]string
-	MUI64S   map[uint64]string
-	MI8S     map[int8]string
-	MUI8S    map[uint8]string
-	SMSI     []map[string]int
-	// Empty interfaces; used to see if we can dig inside one.
-	Empty0 interface{} // nil
-	Empty1 interface{}
-	Empty2 interface{}
-	Empty3 interface{}
-	Empty4 interface{}
-	// Non-empty interfaces.
-	NonEmptyInterface         I
-	NonEmptyInterfacePtS      *I
-	NonEmptyInterfaceNil      I
-	NonEmptyInterfaceTypedNil I
-	// Stringer.
-	Str fmt.Stringer
-	Err error
-	// Pointers
-	PI  *int
-	PS  *string
-	PSI *[]int
-	NIL *int
-	// Function (not method)
-	BinaryFunc      func(string, string) string
-	VariadicFunc    func(...string) string
-	VariadicFuncInt func(int, ...string) string
-	NilOKFunc       func(*int) bool
-	ErrFunc         func() (string, error)
-	PanicFunc       func() string
-	// Template to test evaluation of templates.
-	Tmpl *Template
-	// Unexported field; cannot be accessed by template.
-	unexported int
-}
-
-type S []string
-
-func (S) Method0() string {
-	return "M0"
-}
-
-type U struct {
-	V string
-}
-
-type V struct {
-	j int
-}
-
-func (v *V) String() string {
-	if v == nil {
-		return "nilV"
-	}
-	return fmt.Sprintf("<%d>", v.j)
-}
-
-type W struct {
-	k int
-}
-
-func (w *W) Error() string {
-	if w == nil {
-		return "nilW"
-	}
-	return fmt.Sprintf("[%d]", w.k)
-}
-
-var siVal = I(S{"a", "b"})
-
-var tVal = &T{
-	True:   true,
-	I:      17,
-	U16:    16,
-	X:      "x",
-	S:      "xyz",
-	U:      &U{"v"},
-	V0:     V{6666},
-	V1:     &V{7777}, // leave V2 as nil
-	W0:     W{888},
-	W1:     &W{999}, // leave W2 as nil
-	SI:     []int{3, 4, 5},
-	SICap:  make([]int, 5, 10),
-	AI:     [3]int{3, 4, 5},
-	SB:     []bool{true, false},
-	MSI:    map[string]int{"one": 1, "two": 2, "three": 3},
-	MSIone: map[string]int{"one": 1},
-	MXI:    map[interface{}]int{"one": 1},
-	MII:    map[int]int{1: 1},
-	MI32S:  map[int32]string{1: "one", 2: "two"},
-	MI64S:  map[int64]string{2: "i642", 3: "i643"},
-	MUI32S: map[uint32]string{2: "u322", 3: "u323"},
-	MUI64S: map[uint64]string{2: "ui642", 3: "ui643"},
-	MI8S:   map[int8]string{2: "i82", 3: "i83"},
-	MUI8S:  map[uint8]string{2: "u82", 3: "u83"},
-	SMSI: []map[string]int{
-		{"one": 1, "two": 2},
-		{"eleven": 11, "twelve": 12},
-	},
-	Empty1:                    3,
-	Empty2:                    "empty2",
-	Empty3:                    []int{7, 8},
-	Empty4:                    &U{"UinEmpty"},
-	NonEmptyInterface:         &T{X: "x"},
-	NonEmptyInterfacePtS:      &siVal,
-	NonEmptyInterfaceTypedNil: (*T)(nil),
-	Str:                       bytes.NewBuffer([]byte("foozle")),
-	Err:                       errors.New("erroozle"),
-	PI:                        newInt(23),
-	PS:                        newString("a string"),
-	PSI:                       newIntSlice(21, 22, 23),
-	BinaryFunc:                func(a, b string) string { return fmt.Sprintf("[%s=%s]", a, b) },
-	VariadicFunc:              func(s ...string) string { return fmt.Sprint("<", strings.Join(s, "+"), ">") },
-	VariadicFuncInt:           func(a int, s ...string) string { return fmt.Sprint(a, "=<", strings.Join(s, "+"), ">") },
-	NilOKFunc:                 func(s *int) bool { return s == nil },
-	ErrFunc:                   func() (string, error) { return "bla", nil },
-	PanicFunc:                 func() string { panic("test panic") },
-	Tmpl:                      Must(New("x").Parse("test template")), // "x" is the value of .X
-}
-
-var tSliceOfNil = []*T{nil}
-
-// A non-empty interface.
-type I interface {
-	Method0() string
-}
-
-var iVal I = tVal
-
-// Helpers for creation.
-func newInt(n int) *int {
-	return &n
-}
-
-func newString(s string) *string {
-	return &s
-}
-
-func newIntSlice(n ...int) *[]int {
-	p := new([]int)
-	*p = make([]int, len(n))
-	copy(*p, n)
-	return p
-}
-
-// Simple methods with and without arguments.
-func (t *T) Method0() string {
-	return "M0"
-}
-
-func (t *T) Method1(a int) int {
-	return a
-}
-
-func (t *T) Method2(a uint16, b string) string {
-	return fmt.Sprintf("Method2: %d %s", a, b)
-}
-
-func (t *T) Method3(v interface{}) string {
-	return fmt.Sprintf("Method3: %v", v)
-}
-
-func (t *T) Copy() *T {
-	n := new(T)
-	*n = *t
-	return n
-}
-
-func (t *T) MAdd(a int, b []int) []int {
-	v := make([]int, len(b))
-	for i, x := range b {
-		v[i] = x + a
-	}
-	return v
-}
-
-var myError = errors.New("my error")
-
-// MyError returns a value and an error according to its argument.
-func (t *T) MyError(error bool) (bool, error) {
-	if error {
-		return true, myError
-	}
-	return false, nil
-}
-
-// A few methods to test chaining.
-func (t *T) GetU() *U {
-	return t.U
-}
-
-func (u *U) TrueFalse(b bool) string {
-	if b {
-		return "true"
-	}
-	return ""
-}
-
-func typeOf(arg interface{}) string {
-	return fmt.Sprintf("%T", arg)
-}
-
-type execTest struct {
-	name   string
-	input  string
-	output string
-	data   interface{}
-	ok     bool
-}
-
-// bigInt and bigUint are hex string representing numbers either side
-// of the max int boundary.
-// We do it this way so the test doesn't depend on ints being 32 bits.
-var (
-	bigInt  = fmt.Sprintf("0x%x", int(1<<uint(reflect.TypeOf(0).Bits()-1)-1))
-	bigUint = fmt.Sprintf("0x%x", uint(1<<uint(reflect.TypeOf(0).Bits()-1)))
-)
-
-var execTests = []execTest{
-	// Trivial cases.
-	{"empty", "", "", nil, true},
-	{"text", "some text", "some text", nil, true},
-	{"nil action", "{{nil}}", "", nil, false},
-
-	// Ideal constants.
-	{"ideal int", "{{typeOf 3}}", "int", 0, true},
-	{"ideal float", "{{typeOf 1.0}}", "float64", 0, true},
-	{"ideal exp float", "{{typeOf 1e1}}", "float64", 0, true},
-	{"ideal complex", "{{typeOf 1i}}", "complex128", 0, true},
-	{"ideal int", "{{typeOf " + bigInt + "}}", "int", 0, true},
-	{"ideal too big", "{{typeOf " + bigUint + "}}", "", 0, false},
-	{"ideal nil without type", "{{nil}}", "", 0, false},
-
-	// Fields of structs.
-	{".X", "-{{.X}}-", "-x-", tVal, true},
-	{".U.V", "-{{.U.V}}-", "-v-", tVal, true},
-	{".unexported", "{{.unexported}}", "", tVal, false},
-
-	// Fields on maps.
-	{"map .one", "{{.MSI.one}}", "1", tVal, true},
-	{"map .two", "{{.MSI.two}}", "2", tVal, true},
-	{"map .NO", "{{.MSI.NO}}", "<no value>", tVal, true},
-	{"map .one interface", "{{.MXI.one}}", "1", tVal, true},
-	{"map .WRONG args", "{{.MSI.one 1}}", "", tVal, false},
-	{"map .WRONG type", "{{.MII.one}}", "", tVal, false},
-
-	// Dots of all kinds to test basic evaluation.
-	{"dot int", "<{{.}}>", "<13>", 13, true},
-	{"dot uint", "<{{.}}>", "<14>", uint(14), true},
-	{"dot float", "<{{.}}>", "<15.1>", 15.1, true},
-	{"dot bool", "<{{.}}>", "<true>", true, true},
-	{"dot complex", "<{{.}}>", "<(16.2-17i)>", 16.2 - 17i, true},
-	{"dot string", "<{{.}}>", "<hello>", "hello", true},
-	{"dot slice", "<{{.}}>", "<[-1 -2 -3]>", []int{-1, -2, -3}, true},
-	{"dot map", "<{{.}}>", "<map[two:22]>", map[string]int{"two": 22}, true},
-	{"dot struct", "<{{.}}>", "<{7 seven}>", struct {
-		a int
-		b string
-	}{7, "seven"}, true},
-
-	// Variables.
-	{"$ int", "{{$}}", "123", 123, true},
-	{"$.I", "{{$.I}}", "17", tVal, true},
-	{"$.U.V", "{{$.U.V}}", "v", tVal, true},
-	{"declare in action", "{{$x := $.U.V}}{{$x}}", "v", tVal, true},
-	{"simple assignment", "{{$x := 2}}{{$x = 3}}{{$x}}", "3", tVal, true},
-	{"nested assignment",
-		"{{$x := 2}}{{if true}}{{$x = 3}}{{end}}{{$x}}",
-		"3", tVal, true},
-	{"nested assignment changes the last declaration",
-		"{{$x := 1}}{{if true}}{{$x := 2}}{{if true}}{{$x = 3}}{{end}}{{end}}{{$x}}",
-		"1", tVal, true},
-
-	// Type with String method.
-	{"V{6666}.String()", "-{{.V0}}-", "-<6666>-", tVal, true},
-	{"&V{7777}.String()", "-{{.V1}}-", "-<7777>-", tVal, true},
-	{"(*V)(nil).String()", "-{{.V2}}-", "-nilV-", tVal, true},
-
-	// Type with Error method.
-	{"W{888}.Error()", "-{{.W0}}-", "-[888]-", tVal, true},
-	{"&W{999}.Error()", "-{{.W1}}-", "-[999]-", tVal, true},
-	{"(*W)(nil).Error()", "-{{.W2}}-", "-nilW-", tVal, true},
-
-	// Pointers.
-	{"*int", "{{.PI}}", "23", tVal, true},
-	{"*string", "{{.PS}}", "a string", tVal, true},
-	{"*[]int", "{{.PSI}}", "[21 22 23]", tVal, true},
-	{"*[]int[1]", "{{index .PSI 1}}", "22", tVal, true},
-	{"NIL", "{{.NIL}}", "<nil>", tVal, true},
-
-	// Empty interfaces holding values.
-	{"empty nil", "{{.Empty0}}", "<no value>", tVal, true},
-	{"empty with int", "{{.Empty1}}", "3", tVal, true},
-	{"empty with string", "{{.Empty2}}", "empty2", tVal, true},
-	{"empty with slice", "{{.Empty3}}", "[7 8]", tVal, true},
-	{"empty with struct", "{{.Empty4}}", "{UinEmpty}", tVal, true},
-	{"empty with struct, field", "{{.Empty4.V}}", "UinEmpty", tVal, true},
-
-	// Edge cases with <no value> with an interface value
-	{"field on interface", "{{.foo}}", "<no value>", nil, true},
-	{"field on parenthesized interface", "{{(.).foo}}", "<no value>", nil, true},
-
-	// Issue 31810: Parenthesized first element of pipeline with arguments.
-	// See also TestIssue31810.
-	{"unparenthesized non-function", "{{1 2}}", "", nil, false},
-	{"parenthesized non-function", "{{(1) 2}}", "", nil, false},
-	{"parenthesized non-function with no args", "{{(1)}}", "1", nil, true}, // This is fine.
-
-	// Method calls.
-	{".Method0", "-{{.Method0}}-", "-M0-", tVal, true},
-	{".Method1(1234)", "-{{.Method1 1234}}-", "-1234-", tVal, true},
-	{".Method1(.I)", "-{{.Method1 .I}}-", "-17-", tVal, true},
-	{".Method2(3, .X)", "-{{.Method2 3 .X}}-", "-Method2: 3 x-", tVal, true},
-	{".Method2(.U16, `str`)", "-{{.Method2 .U16 `str`}}-", "-Method2: 16 str-", tVal, true},
-	{".Method2(.U16, $x)", "{{if $x := .X}}-{{.Method2 .U16 $x}}{{end}}-", "-Method2: 16 x-", tVal, true},
-	{".Method3(nil constant)", "-{{.Method3 nil}}-", "-Method3: <nil>-", tVal, true},
-	{".Method3(nil value)", "-{{.Method3 .MXI.unset}}-", "-Method3: <nil>-", tVal, true},
-	{"method on var", "{{if $x := .}}-{{$x.Method2 .U16 $x.X}}{{end}}-", "-Method2: 16 x-", tVal, true},
-	{"method on chained var",
-		"{{range .MSIone}}{{if $.U.TrueFalse $.True}}{{$.U.TrueFalse $.True}}{{else}}WRONG{{end}}{{end}}",
-		"true", tVal, true},
-	{"chained method",
-		"{{range .MSIone}}{{if $.GetU.TrueFalse $.True}}{{$.U.TrueFalse $.True}}{{else}}WRONG{{end}}{{end}}",
-		"true", tVal, true},
-	{"chained method on variable",
-		"{{with $x := .}}{{with .SI}}{{$.GetU.TrueFalse $.True}}{{end}}{{end}}",
-		"true", tVal, true},
-	{".NilOKFunc not nil", "{{call .NilOKFunc .PI}}", "false", tVal, true},
-	{".NilOKFunc nil", "{{call .NilOKFunc nil}}", "true", tVal, true},
-	{"method on nil value from slice", "-{{range .}}{{.Method1 1234}}{{end}}-", "-1234-", tSliceOfNil, true},
-	{"method on typed nil interface value", "{{.NonEmptyInterfaceTypedNil.Method0}}", "M0", tVal, true},
-
-	// Function call builtin.
-	{".BinaryFunc", "{{call .BinaryFunc `1` `2`}}", "[1=2]", tVal, true},
-	{".VariadicFunc0", "{{call .VariadicFunc}}", "<>", tVal, true},
-	{".VariadicFunc2", "{{call .VariadicFunc `he` `llo`}}", "<he+llo>", tVal, true},
-	{".VariadicFuncInt", "{{call .VariadicFuncInt 33 `he` `llo`}}", "33=<he+llo>", tVal, true},
-	{"if .BinaryFunc call", "{{ if .BinaryFunc}}{{call .BinaryFunc `1` `2`}}{{end}}", "[1=2]", tVal, true},
-	{"if not .BinaryFunc call", "{{ if not .BinaryFunc}}{{call .BinaryFunc `1` `2`}}{{else}}No{{end}}", "No", tVal, true},
-	{"Interface Call", `{{stringer .S}}`, "foozle", map[string]interface{}{"S": bytes.NewBufferString("foozle")}, true},
-	{".ErrFunc", "{{call .ErrFunc}}", "bla", tVal, true},
-	{"call nil", "{{call nil}}", "", tVal, false},
-
-	// Erroneous function calls (check args).
-	{".BinaryFuncTooFew", "{{call .BinaryFunc `1`}}", "", tVal, false},
-	{".BinaryFuncTooMany", "{{call .BinaryFunc `1` `2` `3`}}", "", tVal, false},
-	{".BinaryFuncBad0", "{{call .BinaryFunc 1 3}}", "", tVal, false},
-	{".BinaryFuncBad1", "{{call .BinaryFunc `1` 3}}", "", tVal, false},
-	{".VariadicFuncBad0", "{{call .VariadicFunc 3}}", "", tVal, false},
-	{".VariadicFuncIntBad0", "{{call .VariadicFuncInt}}", "", tVal, false},
-	{".VariadicFuncIntBad`", "{{call .VariadicFuncInt `x`}}", "", tVal, false},
-	{".VariadicFuncNilBad", "{{call .VariadicFunc nil}}", "", tVal, false},
-
-	// Pipelines.
-	{"pipeline", "-{{.Method0 | .Method2 .U16}}-", "-Method2: 16 M0-", tVal, true},
-	{"pipeline func", "-{{call .VariadicFunc `llo` | call .VariadicFunc `he` }}-", "-<he+<llo>>-", tVal, true},
-
-	// Nil values aren't missing arguments.
-	{"nil pipeline", "{{ .Empty0 | call .NilOKFunc }}", "true", tVal, true},
-	{"nil call arg", "{{ call .NilOKFunc .Empty0 }}", "true", tVal, true},
-	{"bad nil pipeline", "{{ .Empty0 | .VariadicFunc }}", "", tVal, false},
-
-	// Parenthesized expressions
-	{"parens in pipeline", "{{printf `%d %d %d` (1) (2 | add 3) (add 4 (add 5 6))}}", "1 5 15", tVal, true},
-
-	// Parenthesized expressions with field accesses
-	{"parens: $ in paren", "{{($).X}}", "x", tVal, true},
-	{"parens: $.GetU in paren", "{{($.GetU).V}}", "v", tVal, true},
-	{"parens: $ in paren in pipe", "{{($ | echo).X}}", "x", tVal, true},
-	{"parens: spaces and args", `{{(makemap "up" "down" "left" "right").left}}`, "right", tVal, true},
-
-	// If.
-	{"if true", "{{if true}}TRUE{{end}}", "TRUE", tVal, true},
-	{"if false", "{{if false}}TRUE{{else}}FALSE{{end}}", "FALSE", tVal, true},
-	{"if nil", "{{if nil}}TRUE{{end}}", "", tVal, false},
-	{"if on typed nil interface value", "{{if .NonEmptyInterfaceTypedNil}}TRUE{{ end }}", "", tVal, true},
-	{"if 1", "{{if 1}}NON-ZERO{{else}}ZERO{{end}}", "NON-ZERO", tVal, true},
-	{"if 0", "{{if 0}}NON-ZERO{{else}}ZERO{{end}}", "ZERO", tVal, true},
-	{"if 1.5", "{{if 1.5}}NON-ZERO{{else}}ZERO{{end}}", "NON-ZERO", tVal, true},
-	{"if 0.0", "{{if .FloatZero}}NON-ZERO{{else}}ZERO{{end}}", "ZERO", tVal, true},
-	{"if 1.5i", "{{if 1.5i}}NON-ZERO{{else}}ZERO{{end}}", "NON-ZERO", tVal, true},
-	{"if 0.0i", "{{if .ComplexZero}}NON-ZERO{{else}}ZERO{{end}}", "ZERO", tVal, true},
-	{"if emptystring", "{{if ``}}NON-EMPTY{{else}}EMPTY{{end}}", "EMPTY", tVal, true},
-	{"if string", "{{if `notempty`}}NON-EMPTY{{else}}EMPTY{{end}}", "NON-EMPTY", tVal, true},
-	{"if emptyslice", "{{if .SIEmpty}}NON-EMPTY{{else}}EMPTY{{end}}", "EMPTY", tVal, true},
-	{"if slice", "{{if .SI}}NON-EMPTY{{else}}EMPTY{{end}}", "NON-EMPTY", tVal, true},
-	{"if emptymap", "{{if .MSIEmpty}}NON-EMPTY{{else}}EMPTY{{end}}", "EMPTY", tVal, true},
-	{"if map", "{{if .MSI}}NON-EMPTY{{else}}EMPTY{{end}}", "NON-EMPTY", tVal, true},
-	{"if map unset", "{{if .MXI.none}}NON-ZERO{{else}}ZERO{{end}}", "ZERO", tVal, true},
-	{"if map not unset", "{{if not .MXI.none}}ZERO{{else}}NON-ZERO{{end}}", "ZERO", tVal, true},
-	{"if $x with $y int", "{{if $x := true}}{{with $y := .I}}{{$x}},{{$y}}{{end}}{{end}}", "true,17", tVal, true},
-	{"if $x with $x int", "{{if $x := true}}{{with $x := .I}}{{$x}},{{end}}{{$x}}{{end}}", "17,true", tVal, true},
-	{"if else if", "{{if false}}FALSE{{else if true}}TRUE{{end}}", "TRUE", tVal, true},
-	{"if else chain", "{{if eq 1 3}}1{{else if eq 2 3}}2{{else if eq 3 3}}3{{end}}", "3", tVal, true},
-
-	// Print etc.
-	{"print", `{{print "hello, print"}}`, "hello, print", tVal, true},
-	{"print 123", `{{print 1 2 3}}`, "1 2 3", tVal, true},
-	{"print nil", `{{print nil}}`, "<nil>", tVal, true},
-	{"println", `{{println 1 2 3}}`, "1 2 3\n", tVal, true},
-	{"printf int", `{{printf "%04x" 127}}`, "007f", tVal, true},
-	{"printf float", `{{printf "%g" 3.5}}`, "3.5", tVal, true},
-	{"printf complex", `{{printf "%g" 1+7i}}`, "(1+7i)", tVal, true},
-	{"printf string", `{{printf "%s" "hello"}}`, "hello", tVal, true},
-	{"printf function", `{{printf "%#q" zeroArgs}}`, "`zeroArgs`", tVal, true},
-	{"printf field", `{{printf "%s" .U.V}}`, "v", tVal, true},
-	{"printf method", `{{printf "%s" .Method0}}`, "M0", tVal, true},
-	{"printf dot", `{{with .I}}{{printf "%d" .}}{{end}}`, "17", tVal, true},
-	{"printf var", `{{with $x := .I}}{{printf "%d" $x}}{{end}}`, "17", tVal, true},
-	{"printf lots", `{{printf "%d %s %g %s" 127 "hello" 7-3i .Method0}}`, "127 hello (7-3i) M0", tVal, true},
-
-	// HTML.
-	{"html", `{{html "<script>alert(\"XSS\");</script>"}}`,
-		"&lt;script&gt;alert(&#34;XSS&#34;);&lt;/script&gt;", nil, true},
-	{"html pipeline", `{{printf "<script>alert(\"XSS\");</script>" | html}}`,
-		"&lt;script&gt;alert(&#34;XSS&#34;);&lt;/script&gt;", nil, true},
-	{"html", `{{html .PS}}`, "a string", tVal, true},
-	{"html typed nil", `{{html .NIL}}`, "&lt;nil&gt;", tVal, true},
-	{"html untyped nil", `{{html .Empty0}}`, "&lt;no value&gt;", tVal, true},
-
-	// JavaScript.
-	{"js", `{{js .}}`, `It\'d be nice.`, `It'd be nice.`, true},
-
-	// URL query.
-	{"urlquery", `{{"http://www.example.org/"|urlquery}}`, "http%3A%2F%2Fwww.example.org%2F", nil, true},
-
-	// Booleans
-	{"not", "{{not true}} {{not false}}", "false true", nil, true},
-	{"and", "{{and false 0}} {{and 1 0}} {{and 0 true}} {{and 1 1}}", "false 0 0 1", nil, true},
-	{"or", "{{or 0 0}} {{or 1 0}} {{or 0 true}} {{or 1 1}}", "0 1 true 1", nil, true},
-	{"or short-circuit", "{{or 0 1 (die)}}", "1", nil, true},
-	{"and short-circuit", "{{and 1 0 (die)}}", "0", nil, true},
-	{"or short-circuit2", "{{or 0 0 (die)}}", "", nil, false},
-	{"and short-circuit2", "{{and 1 1 (die)}}", "", nil, false},
-	{"boolean if", "{{if and true 1 `hi`}}TRUE{{else}}FALSE{{end}}", "TRUE", tVal, true},
-	{"boolean if not", "{{if and true 1 `hi` | not}}TRUE{{else}}FALSE{{end}}", "FALSE", nil, true},
-
-	// Indexing.
-	{"slice[0]", "{{index .SI 0}}", "3", tVal, true},
-	{"slice[1]", "{{index .SI 1}}", "4", tVal, true},
-	{"slice[HUGE]", "{{index .SI 10}}", "", tVal, false},
-	{"slice[WRONG]", "{{index .SI `hello`}}", "", tVal, false},
-	{"slice[nil]", "{{index .SI nil}}", "", tVal, false},
-	{"map[one]", "{{index .MSI `one`}}", "1", tVal, true},
-	{"map[two]", "{{index .MSI `two`}}", "2", tVal, true},
-	{"map[NO]", "{{index .MSI `XXX`}}", "0", tVal, true},
-	{"map[nil]", "{{index .MSI nil}}", "", tVal, false},
-	{"map[``]", "{{index .MSI ``}}", "0", tVal, true},
-	{"map[WRONG]", "{{index .MSI 10}}", "", tVal, false},
-	{"double index", "{{index .SMSI 1 `eleven`}}", "11", tVal, true},
-	{"nil[1]", "{{index nil 1}}", "", tVal, false},
-	{"map MI64S", "{{index .MI64S 2}}", "i642", tVal, true},
-	{"map MI32S", "{{index .MI32S 2}}", "two", tVal, true},
-	{"map MUI64S", "{{index .MUI64S 3}}", "ui643", tVal, true},
-	{"map MI8S", "{{index .MI8S 3}}", "i83", tVal, true},
-	{"map MUI8S", "{{index .MUI8S 2}}", "u82", tVal, true},
-	{"index of an interface field", "{{index .Empty3 0}}", "7", tVal, true},
-
-	// Slicing.
-	{"slice[:]", "{{slice .SI}}", "[3 4 5]", tVal, true},
-	{"slice[1:]", "{{slice .SI 1}}", "[4 5]", tVal, true},
-	{"slice[1:2]", "{{slice .SI 1 2}}", "[4]", tVal, true},
-	{"slice[-1:]", "{{slice .SI -1}}", "", tVal, false},
-	{"slice[1:-2]", "{{slice .SI 1 -2}}", "", tVal, false},
-	{"slice[1:2:-1]", "{{slice .SI 1 2 -1}}", "", tVal, false},
-	{"slice[2:1]", "{{slice .SI 2 1}}", "", tVal, false},
-	{"slice[2:2:1]", "{{slice .SI 2 2 1}}", "", tVal, false},
-	{"out of range", "{{slice .SI 4 5}}", "", tVal, false},
-	{"out of range", "{{slice .SI 2 2 5}}", "", tVal, false},
-	{"len(s) < indexes < cap(s)", "{{slice .SICap 6 10}}", "[0 0 0 0]", tVal, true},
-	{"len(s) < indexes < cap(s)", "{{slice .SICap 6 10 10}}", "[0 0 0 0]", tVal, true},
-	{"indexes > cap(s)", "{{slice .SICap 10 11}}", "", tVal, false},
-	{"indexes > cap(s)", "{{slice .SICap 6 10 11}}", "", tVal, false},
-	{"array[:]", "{{slice .AI}}", "[3 4 5]", tVal, true},
-	{"array[1:]", "{{slice .AI 1}}", "[4 5]", tVal, true},
-	{"array[1:2]", "{{slice .AI 1 2}}", "[4]", tVal, true},
-	{"string[:]", "{{slice .S}}", "xyz", tVal, true},
-	{"string[0:1]", "{{slice .S 0 1}}", "x", tVal, true},
-	{"string[1:]", "{{slice .S 1}}", "yz", tVal, true},
-	{"string[1:2]", "{{slice .S 1 2}}", "y", tVal, true},
-	{"out of range", "{{slice .S 1 5}}", "", tVal, false},
-	{"3-index slice of string", "{{slice .S 1 2 2}}", "", tVal, false},
-	{"slice of an interface field", "{{slice .Empty3 0 1}}", "[7]", tVal, true},
-
-	// Len.
-	{"slice", "{{len .SI}}", "3", tVal, true},
-	{"map", "{{len .MSI }}", "3", tVal, true},
-	{"len of int", "{{len 3}}", "", tVal, false},
-	{"len of nothing", "{{len .Empty0}}", "", tVal, false},
-	{"len of an interface field", "{{len .Empty3}}", "2", tVal, true},
-
-	// With.
-	{"with true", "{{with true}}{{.}}{{end}}", "true", tVal, true},
-	{"with false", "{{with false}}{{.}}{{else}}FALSE{{end}}", "FALSE", tVal, true},
-	{"with 1", "{{with 1}}{{.}}{{else}}ZERO{{end}}", "1", tVal, true},
-	{"with 0", "{{with 0}}{{.}}{{else}}ZERO{{end}}", "ZERO", tVal, true},
-	{"with 1.5", "{{with 1.5}}{{.}}{{else}}ZERO{{end}}", "1.5", tVal, true},
-	{"with 0.0", "{{with .FloatZero}}{{.}}{{else}}ZERO{{end}}", "ZERO", tVal, true},
-	{"with 1.5i", "{{with 1.5i}}{{.}}{{else}}ZERO{{end}}", "(0+1.5i)", tVal, true},
-	{"with 0.0i", "{{with .ComplexZero}}{{.}}{{else}}ZERO{{end}}", "ZERO", tVal, true},
-	{"with emptystring", "{{with ``}}{{.}}{{else}}EMPTY{{end}}", "EMPTY", tVal, true},
-	{"with string", "{{with `notempty`}}{{.}}{{else}}EMPTY{{end}}", "notempty", tVal, true},
-	{"with emptyslice", "{{with .SIEmpty}}{{.}}{{else}}EMPTY{{end}}", "EMPTY", tVal, true},
-	{"with slice", "{{with .SI}}{{.}}{{else}}EMPTY{{end}}", "[3 4 5]", tVal, true},
-	{"with emptymap", "{{with .MSIEmpty}}{{.}}{{else}}EMPTY{{end}}", "EMPTY", tVal, true},
-	{"with map", "{{with .MSIone}}{{.}}{{else}}EMPTY{{end}}", "map[one:1]", tVal, true},
-	{"with empty interface, struct field", "{{with .Empty4}}{{.V}}{{end}}", "UinEmpty", tVal, true},
-	{"with $x int", "{{with $x := .I}}{{$x}}{{end}}", "17", tVal, true},
-	{"with $x struct.U.V", "{{with $x := $}}{{$x.U.V}}{{end}}", "v", tVal, true},
-	{"with variable and action", "{{with $x := $}}{{$y := $.U.V}}{{$y}}{{end}}", "v", tVal, true},
-	{"with on typed nil interface value", "{{with .NonEmptyInterfaceTypedNil}}TRUE{{ end }}", "", tVal, true},
-
-	// Range.
-	{"range []int", "{{range .SI}}-{{.}}-{{end}}", "-3--4--5-", tVal, true},
-	{"range empty no else", "{{range .SIEmpty}}-{{.}}-{{end}}", "", tVal, true},
-	{"range []int else", "{{range .SI}}-{{.}}-{{else}}EMPTY{{end}}", "-3--4--5-", tVal, true},
-	{"range empty else", "{{range .SIEmpty}}-{{.}}-{{else}}EMPTY{{end}}", "EMPTY", tVal, true},
-	{"range []int break else", "{{range .SI}}-{{.}}-{{break}}NOTREACHED{{else}}EMPTY{{end}}", "-3-", tVal, true},
-	{"range []int continue else", "{{range .SI}}-{{.}}-{{continue}}NOTREACHED{{else}}EMPTY{{end}}", "-3--4--5-", tVal, true},
-	{"range []bool", "{{range .SB}}-{{.}}-{{end}}", "-true--false-", tVal, true},
-	{"range []int method", "{{range .SI | .MAdd .I}}-{{.}}-{{end}}", "-20--21--22-", tVal, true},
-	{"range map", "{{range .MSI}}-{{.}}-{{end}}", "-1--3--2-", tVal, true},
-	{"range empty map no else", "{{range .MSIEmpty}}-{{.}}-{{end}}", "", tVal, true},
-	{"range map else", "{{range .MSI}}-{{.}}-{{else}}EMPTY{{end}}", "-1--3--2-", tVal, true},
-	{"range empty map else", "{{range .MSIEmpty}}-{{.}}-{{else}}EMPTY{{end}}", "EMPTY", tVal, true},
-	{"range empty interface", "{{range .Empty3}}-{{.}}-{{else}}EMPTY{{end}}", "-7--8-", tVal, true},
-	{"range empty nil", "{{range .Empty0}}-{{.}}-{{end}}", "", tVal, true},
-	{"range $x SI", "{{range $x := .SI}}<{{$x}}>{{end}}", "<3><4><5>", tVal, true},
-	{"range $x $y SI", "{{range $x, $y := .SI}}<{{$x}}={{$y}}>{{end}}", "<0=3><1=4><2=5>", tVal, true},
-	{"range $x MSIone", "{{range $x := .MSIone}}<{{$x}}>{{end}}", "<1>", tVal, true},
-	{"range $x $y MSIone", "{{range $x, $y := .MSIone}}<{{$x}}={{$y}}>{{end}}", "<one=1>", tVal, true},
-	{"range $x PSI", "{{range $x := .PSI}}<{{$x}}>{{end}}", "<21><22><23>", tVal, true},
-	{"declare in range", "{{range $x := .PSI}}<{{$foo:=$x}}{{$x}}>{{end}}", "<21><22><23>", tVal, true},
-	{"range count", `{{range $i, $x := count 5}}[{{$i}}]{{$x}}{{end}}`, "[0]a[1]b[2]c[3]d[4]e", tVal, true},
-	{"range nil count", `{{range $i, $x := count 0}}{{else}}empty{{end}}`, "empty", tVal, true},
-
-	// Cute examples.
-	{"or as if true", `{{or .SI "slice is empty"}}`, "[3 4 5]", tVal, true},
-	{"or as if false", `{{or .SIEmpty "slice is empty"}}`, "slice is empty", tVal, true},
-
-	// Error handling.
-	{"error method, error", "{{.MyError true}}", "", tVal, false},
-	{"error method, no error", "{{.MyError false}}", "false", tVal, true},
-
-	// Numbers
-	{"decimal", "{{print 1234}}", "1234", tVal, true},
-	{"decimal _", "{{print 12_34}}", "1234", tVal, true},
-	{"binary", "{{print 0b101}}", "5", tVal, true},
-	{"binary _", "{{print 0b_1_0_1}}", "5", tVal, true},
-	{"BINARY", "{{print 0B101}}", "5", tVal, true},
-	{"octal0", "{{print 0377}}", "255", tVal, true},
-	{"octal", "{{print 0o377}}", "255", tVal, true},
-	{"octal _", "{{print 0o_3_7_7}}", "255", tVal, true},
-	{"OCTAL", "{{print 0O377}}", "255", tVal, true},
-	{"hex", "{{print 0x123}}", "291", tVal, true},
-	{"hex _", "{{print 0x1_23}}", "291", tVal, true},
-	{"HEX", "{{print 0X123ABC}}", "1194684", tVal, true},
-	{"float", "{{print 123.4}}", "123.4", tVal, true},
-	{"float _", "{{print 0_0_1_2_3.4}}", "123.4", tVal, true},
-	{"hex float", "{{print +0x1.ep+2}}", "7.5", tVal, true},
-	{"hex float _", "{{print +0x_1.e_0p+0_2}}", "7.5", tVal, true},
-	{"HEX float", "{{print +0X1.EP+2}}", "7.5", tVal, true},
-	{"print multi", "{{print 1_2_3_4 7.5_00_00_00}}", "1234 7.5", tVal, true},
-	{"print multi2", "{{print 1234 0x0_1.e_0p+02}}", "1234 7.5", tVal, true},
-
-	// Fixed bugs.
-	// Must separate dot and receiver; otherwise args are evaluated with dot set to variable.
-	{"bug0", "{{range .MSIone}}{{if $.Method1 .}}X{{end}}{{end}}", "X", tVal, true},
-	// Do not loop endlessly in indirect for non-empty interfaces.
-	// The bug appears with *interface only; looped forever.
-	{"bug1", "{{.Method0}}", "M0", &iVal, true},
-	// Was taking address of interface field, so method set was empty.
-	{"bug2", "{{$.NonEmptyInterface.Method0}}", "M0", tVal, true},
-	// Struct values were not legal in with - mere oversight.
-	{"bug3", "{{with $}}{{.Method0}}{{end}}", "M0", tVal, true},
-	// Nil interface values in if.
-	{"bug4", "{{if .Empty0}}non-nil{{else}}nil{{end}}", "nil", tVal, true},
-	// Stringer.
-	{"bug5", "{{.Str}}", "foozle", tVal, true},
-	{"bug5a", "{{.Err}}", "erroozle", tVal, true},
-	// Args need to be indirected and dereferenced sometimes.
-	{"bug6a", "{{vfunc .V0 .V1}}", "vfunc", tVal, true},
-	{"bug6b", "{{vfunc .V0 .V0}}", "vfunc", tVal, true},
-	{"bug6c", "{{vfunc .V1 .V0}}", "vfunc", tVal, true},
-	{"bug6d", "{{vfunc .V1 .V1}}", "vfunc", tVal, true},
-	// Legal parse but illegal execution: non-function should have no arguments.
-	{"bug7a", "{{3 2}}", "", tVal, false},
-	{"bug7b", "{{$x := 1}}{{$x 2}}", "", tVal, false},
-	{"bug7c", "{{$x := 1}}{{3 | $x}}", "", tVal, false},
-	// Pipelined arg was not being type-checked.
-	{"bug8a", "{{3|oneArg}}", "", tVal, false},
-	{"bug8b", "{{4|dddArg 3}}", "", tVal, false},
-	// A bug was introduced that broke map lookups for lower-case names.
-	{"bug9", "{{.cause}}", "neglect", map[string]string{"cause": "neglect"}, true},
-	// Field chain starting with function did not work.
-	{"bug10", "{{mapOfThree.three}}-{{(mapOfThree).three}}", "3-3", 0, true},
-	// Dereferencing nil pointer while evaluating function arguments should not panic. Issue 7333.
-	{"bug11", "{{valueString .PS}}", "", T{}, false},
-	// 0xef gave constant type float64. Issue 8622.
-	{"bug12xe", "{{printf `%T` 0xef}}", "int", T{}, true},
-	{"bug12xE", "{{printf `%T` 0xEE}}", "int", T{}, true},
-	{"bug12Xe", "{{printf `%T` 0Xef}}", "int", T{}, true},
-	{"bug12XE", "{{printf `%T` 0XEE}}", "int", T{}, true},
-	// Chained nodes did not work as arguments. Issue 8473.
-	{"bug13", "{{print (.Copy).I}}", "17", tVal, true},
-	// Didn't protect against nil or literal values in field chains.
-	{"bug14a", "{{(nil).True}}", "", tVal, false},
-	{"bug14b", "{{$x := nil}}{{$x.anything}}", "", tVal, false},
-	{"bug14c", `{{$x := (1.0)}}{{$y := ("hello")}}{{$x.anything}}{{$y.true}}`, "", tVal, false},
-	// Didn't call validateType on function results. Issue 10800.
-	{"bug15", "{{valueString returnInt}}", "", tVal, false},
-	// Variadic function corner cases. Issue 10946.
-	{"bug16a", "{{true|printf}}", "", tVal, false},
-	{"bug16b", "{{1|printf}}", "", tVal, false},
-	{"bug16c", "{{1.1|printf}}", "", tVal, false},
-	{"bug16d", "{{'x'|printf}}", "", tVal, false},
-	{"bug16e", "{{0i|printf}}", "", tVal, false},
-	{"bug16f", "{{true|twoArgs \"xxx\"}}", "", tVal, false},
-	{"bug16g", "{{\"aaa\" |twoArgs \"bbb\"}}", "twoArgs=bbbaaa", tVal, true},
-	{"bug16h", "{{1|oneArg}}", "", tVal, false},
-	{"bug16i", "{{\"aaa\"|oneArg}}", "oneArg=aaa", tVal, true},
-	{"bug16j", "{{1+2i|printf \"%v\"}}", "(1+2i)", tVal, true},
-	{"bug16k", "{{\"aaa\"|printf }}", "aaa", tVal, true},
-	{"bug17a", "{{.NonEmptyInterface.X}}", "x", tVal, true},
-	{"bug17b", "-{{.NonEmptyInterface.Method1 1234}}-", "-1234-", tVal, true},
-	{"bug17c", "{{len .NonEmptyInterfacePtS}}", "2", tVal, true},
-	{"bug17d", "{{index .NonEmptyInterfacePtS 0}}", "a", tVal, true},
-	{"bug17e", "{{range .NonEmptyInterfacePtS}}-{{.}}-{{end}}", "-a--b-", tVal, true},
-
-	// More variadic function corner cases. Some runes would get evaluated
-	// as constant floats instead of ints. Issue 34483.
-	{"bug18a", "{{eq . '.'}}", "true", '.', true},
-	{"bug18b", "{{eq . 'e'}}", "true", 'e', true},
-	{"bug18c", "{{eq . 'P'}}", "true", 'P', true},
-}
-
-func zeroArgs() string {
-	return "zeroArgs"
-}
-
-func oneArg(a string) string {
-	return "oneArg=" + a
-}
-
-func twoArgs(a, b string) string {
-	return "twoArgs=" + a + b
-}
-
-func dddArg(a int, b ...string) string {
-	return fmt.Sprintln(a, b)
-}
-
-// count returns a channel that will deliver n sequential 1-letter strings starting at "a"
-func count(n int) chan string {
-	if n == 0 {
-		return nil
-	}
-	c := make(chan string)
-	go func() {
-		for i := 0; i < n; i++ {
-			c <- "abcdefghijklmnop"[i : i+1]
-		}
-		close(c)
-	}()
-	return c
-}
-
-// vfunc takes a *V and a V
-func vfunc(V, *V) string {
-	return "vfunc"
-}
-
-// valueString takes a string, not a pointer.
-func valueString(v string) string {
-	return "value is ignored"
-}
-
-// returnInt returns an int
-func returnInt() int {
-	return 7
-}
-
-func add(args ...int) int {
-	sum := 0
-	for _, x := range args {
-		sum += x
-	}
-	return sum
-}
-
-func echo(arg interface{}) interface{} {
-	return arg
-}
-
-func makemap(arg ...string) map[string]string {
-	if len(arg)%2 != 0 {
-		panic("bad makemap")
-	}
-	m := make(map[string]string)
-	for i := 0; i < len(arg); i += 2 {
-		m[arg[i]] = arg[i+1]
-	}
-	return m
-}
-
-func stringer(s fmt.Stringer) string {
-	return s.String()
-}
-
-func mapOfThree() interface{} {
-	return map[string]int{"three": 3}
-}
-
-func testExecute(execTests []execTest, template *Template, t *testing.T) {
-	b := new(bytes.Buffer)
-	funcs := FuncMap{
-		"add":         add,
-		"count":       count,
-		"dddArg":      dddArg,
-		"die":         func() bool { panic("die") },
-		"echo":        echo,
-		"makemap":     makemap,
-		"mapOfThree":  mapOfThree,
-		"oneArg":      oneArg,
-		"returnInt":   returnInt,
-		"stringer":    stringer,
-		"twoArgs":     twoArgs,
-		"typeOf":      typeOf,
-		"valueString": valueString,
-		"vfunc":       vfunc,
-		"zeroArgs":    zeroArgs,
-	}
-	for _, test := range execTests {
-		var tmpl *Template
-		var err error
-		if template == nil {
-			tmpl, err = New(test.name).Funcs(funcs).Parse(test.input)
-		} else {
-			tmpl, err = template.New(test.name).Funcs(funcs).Parse(test.input)
-		}
-		if err != nil {
-			t.Errorf("%s: parse error: %s", test.name, err)
-			continue
-		}
-		b.Reset()
-		err = tmpl.Execute(b, test.data)
-		switch {
-		case !test.ok && err == nil:
-			t.Errorf("%s: expected error; got none", test.name)
-			continue
-		case test.ok && err != nil:
-			t.Errorf("%s: unexpected execute error: %s", test.name, err)
-			continue
-		case !test.ok && err != nil:
-			// expected error, got one
-			if *debug {
-				fmt.Printf("%s: %s\n\t%s\n", test.name, test.input, err)
-			}
-		}
-		result := b.String()
-		if result != test.output {
-			t.Errorf("%s: expected\n\t%q\ngot\n\t%q", test.name, test.output, result)
-		}
-	}
-}
-
-func TestExecute(t *testing.T) {
-	testExecute(execTests, nil, t)
-}
-
-var delimPairs = []string{
-	"", "", // default
-	"{{", "}}", // same as default
-	"<<", ">>", // distinct
-	"|", "|", // same
-	"(日)", "(本)", // peculiar
-}
-
-func TestDelims(t *testing.T) {
-	const hello = "Hello, world"
-	var value = struct{ Str string }{hello}
-	for i := 0; i < len(delimPairs); i += 2 {
-		text := ".Str"
-		left := delimPairs[i+0]
-		trueLeft := left
-		right := delimPairs[i+1]
-		trueRight := right
-		if left == "" { // default case
-			trueLeft = "{{"
-		}
-		if right == "" { // default case
-			trueRight = "}}"
-		}
-		text = trueLeft + text + trueRight
-		// Now add a comment
-		text += trueLeft + "/*comment*/" + trueRight
-		// Now add  an action containing a string.
-		text += trueLeft + `"` + trueLeft + `"` + trueRight
-		// At this point text looks like `{{.Str}}{{/*comment*/}}{{"{{"}}`.
-		tmpl, err := New("delims").Delims(left, right).Parse(text)
-		if err != nil {
-			t.Fatalf("delim %q text %q parse err %s", left, text, err)
-		}
-		var b = new(bytes.Buffer)
-		err = tmpl.Execute(b, value)
-		if err != nil {
-			t.Fatalf("delim %q exec err %s", left, err)
-		}
-		if b.String() != hello+trueLeft {
-			t.Errorf("expected %q got %q", hello+trueLeft, b.String())
-		}
-	}
-}
-
-// Check that an error from a method flows back to the top.
-func TestExecuteError(t *testing.T) {
-	b := new(bytes.Buffer)
-	tmpl := New("error")
-	_, err := tmpl.Parse("{{.MyError true}}")
-	if err != nil {
-		t.Fatalf("parse error: %s", err)
-	}
-	err = tmpl.Execute(b, tVal)
-	if err == nil {
-		t.Errorf("expected error; got none")
-	} else if !strings.Contains(err.Error(), myError.Error()) {
-		if *debug {
-			fmt.Printf("test execute error: %s\n", err)
-		}
-		t.Errorf("expected myError; got %s", err)
-	}
-}
-
-const execErrorText = `line 1
-line 2
-line 3
-{{template "one" .}}
-{{define "one"}}{{template "two" .}}{{end}}
-{{define "two"}}{{template "three" .}}{{end}}
-{{define "three"}}{{index "hi" $}}{{end}}`
-
-// Check that an error from a nested template contains all the relevant information.
-func TestExecError(t *testing.T) {
-	tmpl, err := New("top").Parse(execErrorText)
-	if err != nil {
-		t.Fatal("parse error:", err)
-	}
-	var b bytes.Buffer
-	err = tmpl.Execute(&b, 5) // 5 is out of range indexing "hi"
-	if err == nil {
-		t.Fatal("expected error")
-	}
-	const want = `template: top:7:20: executing "three" at <index "hi" $>: error calling index: index out of range: 5`
-	got := err.Error()
-	if got != want {
-		t.Errorf("expected\n%q\ngot\n%q", want, got)
-	}
-}
-
-type CustomError struct{}
-
-func (*CustomError) Error() string { return "heyo !" }
-
-// Check that a custom error can be returned.
-func TestExecError_CustomError(t *testing.T) {
-	failingFunc := func() (string, error) {
-		return "", &CustomError{}
-	}
-	tmpl := Must(New("top").Funcs(FuncMap{
-		"err": failingFunc,
-	}).Parse("{{ err }}"))
-
-	var b bytes.Buffer
-	err := tmpl.Execute(&b, nil)
-
-	var e *CustomError
-	if !errors.As(err, &e) {
-		t.Fatalf("expected custom error; got %s", err)
-	}
-}
-
-func TestJSEscaping(t *testing.T) {
-	testCases := []struct {
-		in, exp string
-	}{
-		{`a`, `a`},
-		{`'foo`, `\'foo`},
-		{`Go "jump" \`, `Go \"jump\" \\`},
-		{`Yukihiro says "今日は世界"`, `Yukihiro says \"今日は世界\"`},
-		{"unprintable \uFDFF", `unprintable \uFDFF`},
-		{`<html>`, `\u003Chtml\u003E`},
-		{`no = in attributes`, `no \u003D in attributes`},
-		{`&#x27; does not become HTML entity`, `\u0026#x27; does not become HTML entity`},
-	}
-	for _, tc := range testCases {
-		s := JSEscapeString(tc.in)
-		if s != tc.exp {
-			t.Errorf("JS escaping [%s] got [%s] want [%s]", tc.in, s, tc.exp)
-		}
-	}
-}
-
-// A nice example: walk a binary tree.
-
-type Tree struct {
-	Val         int
-	Left, Right *Tree
-}
-
-// Use different delimiters to test Set.Delims.
-// Also test the trimming of leading and trailing spaces.
-const treeTemplate = `
-	(- define "tree" -)
-	[
-		(- .Val -)
-		(- with .Left -)
-			(template "tree" . -)
-		(- end -)
-		(- with .Right -)
-			(- template "tree" . -)
-		(- end -)
-	]
-	(- end -)
-`
-
-func TestTree(t *testing.T) {
-	var tree = &Tree{
-		1,
-		&Tree{
-			2, &Tree{
-				3,
-				&Tree{
-					4, nil, nil,
-				},
-				nil,
-			},
-			&Tree{
-				5,
-				&Tree{
-					6, nil, nil,
-				},
-				nil,
-			},
-		},
-		&Tree{
-			7,
-			&Tree{
-				8,
-				&Tree{
-					9, nil, nil,
-				},
-				nil,
-			},
-			&Tree{
-				10,
-				&Tree{
-					11, nil, nil,
-				},
-				nil,
-			},
-		},
-	}
-	tmpl, err := New("root").Delims("(", ")").Parse(treeTemplate)
-	if err != nil {
-		t.Fatal("parse error:", err)
-	}
-	var b bytes.Buffer
-	const expect = "[1[2[3[4]][5[6]]][7[8[9]][10[11]]]]"
-	// First by looking up the template.
-	err = tmpl.Lookup("tree").Execute(&b, tree)
-	if err != nil {
-		t.Fatal("exec error:", err)
-	}
-	result := b.String()
-	if result != expect {
-		t.Errorf("expected %q got %q", expect, result)
-	}
-	// Then direct to execution.
-	b.Reset()
-	err = tmpl.ExecuteTemplate(&b, "tree", tree)
-	if err != nil {
-		t.Fatal("exec error:", err)
-	}
-	result = b.String()
-	if result != expect {
-		t.Errorf("expected %q got %q", expect, result)
-	}
-}
-
-func TestExecuteOnNewTemplate(t *testing.T) {
-	// This is issue 3872.
-	New("Name").Templates()
-	// This is issue 11379.
-	new(Template).Templates()
-	new(Template).Parse("")
-	new(Template).New("abc").Parse("")
-	new(Template).Execute(nil, nil)                // returns an error (but does not crash)
-	new(Template).ExecuteTemplate(nil, "XXX", nil) // returns an error (but does not crash)
-}
-
-const testTemplates = `{{define "one"}}one{{end}}{{define "two"}}two{{end}}`
-
-func TestMessageForExecuteEmpty(t *testing.T) {
-	// Test a truly empty template.
-	tmpl := New("empty")
-	var b bytes.Buffer
-	err := tmpl.Execute(&b, 0)
-	if err == nil {
-		t.Fatal("expected initial error")
-	}
-	got := err.Error()
-	want := `template: empty: "empty" is an incomplete or empty template`
-	if got != want {
-		t.Errorf("expected error %s got %s", want, got)
-	}
-	// Add a non-empty template to check that the error is helpful.
-	tests, err := New("").Parse(testTemplates)
-	if err != nil {
-		t.Fatal(err)
-	}
-	tmpl.AddParseTree("secondary", tests.Tree)
-	err = tmpl.Execute(&b, 0)
-	if err == nil {
-		t.Fatal("expected second error")
-	}
-	got = err.Error()
-	want = `template: empty: "empty" is an incomplete or empty template`
-	if got != want {
-		t.Errorf("expected error %s got %s", want, got)
-	}
-	// Make sure we can execute the secondary.
-	err = tmpl.ExecuteTemplate(&b, "secondary", 0)
-	if err != nil {
-		t.Fatal(err)
-	}
-}
-
-func TestFinalForPrintf(t *testing.T) {
-	tmpl, err := New("").Parse(`{{"x" | printf}}`)
-	if err != nil {
-		t.Fatal(err)
-	}
-	var b bytes.Buffer
-	err = tmpl.Execute(&b, 0)
-	if err != nil {
-		t.Fatal(err)
-	}
-}
-
-type cmpTest struct {
-	expr  string
-	truth string
-	ok    bool
-}
-
-var cmpTests = []cmpTest{
-	{"eq true true", "true", true},
-	{"eq true false", "false", true},
-	{"eq 1+2i 1+2i", "true", true},
-	{"eq 1+2i 1+3i", "false", true},
-	{"eq 1.5 1.5", "true", true},
-	{"eq 1.5 2.5", "false", true},
-	{"eq 1 1", "true", true},
-	{"eq 1 2", "false", true},
-	{"eq `xy` `xy`", "true", true},
-	{"eq `xy` `xyz`", "false", true},
-	{"eq .Uthree .Uthree", "true", true},
-	{"eq .Uthree .Ufour", "false", true},
-	{"eq 3 4 5 6 3", "true", true},
-	{"eq 3 4 5 6 7", "false", true},
-	{"ne true true", "false", true},
-	{"ne true false", "true", true},
-	{"ne 1+2i 1+2i", "false", true},
-	{"ne 1+2i 1+3i", "true", true},
-	{"ne 1.5 1.5", "false", true},
-	{"ne 1.5 2.5", "true", true},
-	{"ne 1 1", "false", true},
-	{"ne 1 2", "true", true},
-	{"ne `xy` `xy`", "false", true},
-	{"ne `xy` `xyz`", "true", true},
-	{"ne .Uthree .Uthree", "false", true},
-	{"ne .Uthree .Ufour", "true", true},
-	{"lt 1.5 1.5", "false", true},
-	{"lt 1.5 2.5", "true", true},
-	{"lt 1 1", "false", true},
-	{"lt 1 2", "true", true},
-	{"lt `xy` `xy`", "false", true},
-	{"lt `xy` `xyz`", "true", true},
-	{"lt .Uthree .Uthree", "false", true},
-	{"lt .Uthree .Ufour", "true", true},
-	{"le 1.5 1.5", "true", true},
-	{"le 1.5 2.5", "true", true},
-	{"le 2.5 1.5", "false", true},
-	{"le 1 1", "true", true},
-	{"le 1 2", "true", true},
-	{"le 2 1", "false", true},
-	{"le `xy` `xy`", "true", true},
-	{"le `xy` `xyz`", "true", true},
-	{"le `xyz` `xy`", "false", true},
-	{"le .Uthree .Uthree", "true", true},
-	{"le .Uthree .Ufour", "true", true},
-	{"le .Ufour .Uthree", "false", true},
-	{"gt 1.5 1.5", "false", true},
-	{"gt 1.5 2.5", "false", true},
-	{"gt 1 1", "false", true},
-	{"gt 2 1", "true", true},
-	{"gt 1 2", "false", true},
-	{"gt `xy` `xy`", "false", true},
-	{"gt `xy` `xyz`", "false", true},
-	{"gt .Uthree .Uthree", "false", true},
-	{"gt .Uthree .Ufour", "false", true},
-	{"gt .Ufour .Uthree", "true", true},
-	{"ge 1.5 1.5", "true", true},
-	{"ge 1.5 2.5", "false", true},
-	{"ge 2.5 1.5", "true", true},
-	{"ge 1 1", "true", true},
-	{"ge 1 2", "false", true},
-	{"ge 2 1", "true", true},
-	{"ge `xy` `xy`", "true", true},
-	{"ge `xy` `xyz`", "false", true},
-	{"ge `xyz` `xy`", "true", true},
-	{"ge .Uthree .Uthree", "true", true},
-	{"ge .Uthree .Ufour", "false", true},
-	{"ge .Ufour .Uthree", "true", true},
-	// Mixing signed and unsigned integers.
-	{"eq .Uthree .Three", "true", true},
-	{"eq .Three .Uthree", "true", true},
-	{"le .Uthree .Three", "true", true},
-	{"le .Three .Uthree", "true", true},
-	{"ge .Uthree .Three", "true", true},
-	{"ge .Three .Uthree", "true", true},
-	{"lt .Uthree .Three", "false", true},
-	{"lt .Three .Uthree", "false", true},
-	{"gt .Uthree .Three", "false", true},
-	{"gt .Three .Uthree", "false", true},
-	{"eq .Ufour .Three", "false", true},
-	{"lt .Ufour .Three", "false", true},
-	{"gt .Ufour .Three", "true", true},
-	{"eq .NegOne .Uthree", "false", true},
-	{"eq .Uthree .NegOne", "false", true},
-	{"ne .NegOne .Uthree", "true", true},
-	{"ne .Uthree .NegOne", "true", true},
-	{"lt .NegOne .Uthree", "true", true},
-	{"lt .Uthree .NegOne", "false", true},
-	{"le .NegOne .Uthree", "true", true},
-	{"le .Uthree .NegOne", "false", true},
-	{"gt .NegOne .Uthree", "false", true},
-	{"gt .Uthree .NegOne", "true", true},
-	{"ge .NegOne .Uthree", "false", true},
-	{"ge .Uthree .NegOne", "true", true},
-	{"eq (index `x` 0) 'x'", "true", true}, // The example that triggered this rule.
-	{"eq (index `x` 0) 'y'", "false", true},
-	{"eq .V1 .V2", "true", true},
-	{"eq .Ptr .Ptr", "true", true},
-	{"eq .Ptr .NilPtr", "false", true},
-	{"eq .NilPtr .NilPtr", "true", true},
-	{"eq .Iface1 .Iface1", "true", true},
-	{"eq .Iface1 .NilIface", "false", true},
-	{"eq .NilIface .NilIface", "true", true},
-	{"eq .NilIface .Iface1", "false", true},
-	{"eq .NilIface 0", "false", true},
-	{"eq 0 .NilIface", "false", true},
-	// Errors
-	{"eq `xy` 1", "", false},       // Different types.
-	{"eq 2 2.0", "", false},        // Different types.
-	{"lt true true", "", false},    // Unordered types.
-	{"lt 1+0i 1+0i", "", false},    // Unordered types.
-	{"eq .Ptr 1", "", false},       // Incompatible types.
-	{"eq .Ptr .NegOne", "", false}, // Incompatible types.
-	{"eq .Map .Map", "", false},    // Uncomparable types.
-	{"eq .Map .V1", "", false},     // Uncomparable types.
-}
-
-func TestComparison(t *testing.T) {
-	b := new(bytes.Buffer)
-	var cmpStruct = struct {
-		Uthree, Ufour    uint
-		NegOne, Three    int
-		Ptr, NilPtr      *int
-		Map              map[int]int
-		V1, V2           V
-		Iface1, NilIface fmt.Stringer
-	}{
-		Uthree: 3,
-		Ufour:  4,
-		NegOne: -1,
-		Three:  3,
-		Ptr:    new(int),
-		Iface1: b,
-	}
-	for _, test := range cmpTests {
-		text := fmt.Sprintf("{{if %s}}true{{else}}false{{end}}", test.expr)
-		tmpl, err := New("empty").Parse(text)
-		if err != nil {
-			t.Fatalf("%q: %s", test.expr, err)
-		}
-		b.Reset()
-		err = tmpl.Execute(b, &cmpStruct)
-		if test.ok && err != nil {
-			t.Errorf("%s errored incorrectly: %s", test.expr, err)
-			continue
-		}
-		if !test.ok && err == nil {
-			t.Errorf("%s did not error", test.expr)
-			continue
-		}
-		if b.String() != test.truth {
-			t.Errorf("%s: want %s; got %s", test.expr, test.truth, b.String())
-		}
-	}
-}
-
-func TestMissingMapKey(t *testing.T) {
-	data := map[string]int{
-		"x": 99,
-	}
-	tmpl, err := New("t1").Parse("{{.x}} {{.y}}")
-	if err != nil {
-		t.Fatal(err)
-	}
-	var b bytes.Buffer
-	// By default, just get "<no value>"
-	err = tmpl.Execute(&b, data)
-	if err != nil {
-		t.Fatal(err)
-	}
-	want := "99 <no value>"
-	got := b.String()
-	if got != want {
-		t.Errorf("got %q; expected %q", got, want)
-	}
-	// Same if we set the option explicitly to the default.
-	tmpl.Option("missingkey=default")
-	b.Reset()
-	err = tmpl.Execute(&b, data)
-	if err != nil {
-		t.Fatal("default:", err)
-	}
-	want = "99 <no value>"
-	got = b.String()
-	if got != want {
-		t.Errorf("got %q; expected %q", got, want)
-	}
-	// Next we ask for a zero value
-	tmpl.Option("missingkey=zero")
-	b.Reset()
-	err = tmpl.Execute(&b, data)
-	if err != nil {
-		t.Fatal("zero:", err)
-	}
-	want = "99 0"
-	got = b.String()
-	if got != want {
-		t.Errorf("got %q; expected %q", got, want)
-	}
-	// Now we ask for an error.
-	tmpl.Option("missingkey=error")
-	err = tmpl.Execute(&b, data)
-	if err == nil {
-		t.Errorf("expected error; got none")
-	}
-	// same Option, but now a nil interface: ask for an error
-	err = tmpl.Execute(&b, nil)
-	t.Log(err)
-	if err == nil {
-		t.Errorf("expected error for nil-interface; got none")
-	}
-}
-
-// Test that the error message for multiline unterminated string
-// refers to the line number of the opening quote.
-func TestUnterminatedStringError(t *testing.T) {
-	_, err := New("X").Parse("hello\n\n{{`unterminated\n\n\n\n}}\n some more\n\n")
-	if err == nil {
-		t.Fatal("expected error")
-	}
-	str := err.Error()
-	if !strings.Contains(str, "X:3: unterminated raw quoted string") {
-		t.Fatalf("unexpected error: %s", str)
-	}
-}
-
-const alwaysErrorText = "always be failing"
-
-var alwaysError = errors.New(alwaysErrorText)
-
-type ErrorWriter int
-
-func (e ErrorWriter) Write(p []byte) (int, error) {
-	return 0, alwaysError
-}
-
-func TestExecuteGivesExecError(t *testing.T) {
-	// First, a non-execution error shouldn't be an ExecError.
-	tmpl, err := New("X").Parse("hello")
-	if err != nil {
-		t.Fatal(err)
-	}
-	err = tmpl.Execute(ErrorWriter(0), 0)
-	if err == nil {
-		t.Fatal("expected error; got none")
-	}
-	if err.Error() != alwaysErrorText {
-		t.Errorf("expected %q error; got %q", alwaysErrorText, err)
-	}
-	// This one should be an ExecError.
-	tmpl, err = New("X").Parse("hello, {{.X.Y}}")
-	if err != nil {
-		t.Fatal(err)
-	}
-	err = tmpl.Execute(ioutil.Discard, 0)
-	if err == nil {
-		t.Fatal("expected error; got none")
-	}
-	eerr, ok := err.(ExecError)
-	if !ok {
-		t.Fatalf("did not expect ExecError %s", eerr)
-	}
-	expect := "field X in type int"
-	if !strings.Contains(err.Error(), expect) {
-		t.Errorf("expected %q; got %q", expect, err)
-	}
-}
-
-func funcNameTestFunc() int {
-	return 0
-}
-
-func TestGoodFuncNames(t *testing.T) {
-	names := []string{
-		"_",
-		"a",
-		"a1",
-		"a1",
-		"Ӵ",
-	}
-	for _, name := range names {
-		tmpl := New("X").Funcs(
-			FuncMap{
-				name: funcNameTestFunc,
-			},
-		)
-		if tmpl == nil {
-			t.Fatalf("nil result for %q", name)
-		}
-	}
-}
-
-func TestBadFuncNames(t *testing.T) {
-	names := []string{
-		"",
-		"2",
-		"a-b",
-	}
-	for _, name := range names {
-		testBadFuncName(name, t)
-	}
-}
-
-func testBadFuncName(name string, t *testing.T) {
-	t.Helper()
-	defer func() {
-		recover()
-	}()
-	New("X").Funcs(
-		FuncMap{
-			name: funcNameTestFunc,
-		},
-	)
-	// If we get here, the name did not cause a panic, which is how Funcs
-	// reports an error.
-	t.Errorf("%q succeeded incorrectly as function name", name)
-}
-
-func TestBlock(t *testing.T) {
-	const (
-		input   = `a({{block "inner" .}}bar({{.}})baz{{end}})b`
-		want    = `a(bar(hello)baz)b`
-		overlay = `{{define "inner"}}foo({{.}})bar{{end}}`
-		want2   = `a(foo(goodbye)bar)b`
-	)
-	tmpl, err := New("outer").Parse(input)
-	if err != nil {
-		t.Fatal(err)
-	}
-	tmpl2, err := Must(tmpl.Clone()).Parse(overlay)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	var buf bytes.Buffer
-	if err := tmpl.Execute(&buf, "hello"); err != nil {
-		t.Fatal(err)
-	}
-	if got := buf.String(); got != want {
-		t.Errorf("got %q, want %q", got, want)
-	}
-
-	buf.Reset()
-	if err := tmpl2.Execute(&buf, "goodbye"); err != nil {
-		t.Fatal(err)
-	}
-	if got := buf.String(); got != want2 {
-		t.Errorf("got %q, want %q", got, want2)
-	}
-}
-
-func TestEvalFieldErrors(t *testing.T) {
-	tests := []struct {
-		name, src string
-		value     interface{}
-		want      string
-	}{
-		{
-			// Check that calling an invalid field on nil pointer
-			// prints a field error instead of a distracting nil
-			// pointer error. https://golang.org/issue/15125
-			"MissingFieldOnNil",
-			"{{.MissingField}}",
-			(*T)(nil),
-			"can't evaluate field MissingField in type *template.T",
-		},
-		{
-			"MissingFieldOnNonNil",
-			"{{.MissingField}}",
-			&T{},
-			"can't evaluate field MissingField in type *template.T",
-		},
-		{
-			"ExistingFieldOnNil",
-			"{{.X}}",
-			(*T)(nil),
-			"nil pointer evaluating *template.T.X",
-		},
-		{
-			"MissingKeyOnNilMap",
-			"{{.MissingKey}}",
-			(*map[string]string)(nil),
-			"nil pointer evaluating *map[string]string.MissingKey",
-		},
-		{
-			"MissingKeyOnNilMapPtr",
-			"{{.MissingKey}}",
-			(*map[string]string)(nil),
-			"nil pointer evaluating *map[string]string.MissingKey",
-		},
-		{
-			"MissingKeyOnMapPtrToNil",
-			"{{.MissingKey}}",
-			&map[string]string{},
-			"<nil>",
-		},
-	}
-	for _, tc := range tests {
-		t.Run(tc.name, func(t *testing.T) {
-			tmpl := Must(New("tmpl").Parse(tc.src))
-			err := tmpl.Execute(ioutil.Discard, tc.value)
-			got := "<nil>"
-			if err != nil {
-				got = err.Error()
-			}
-			if !strings.HasSuffix(got, tc.want) {
-				t.Fatalf("got error %q, want %q", got, tc.want)
-			}
-		})
-	}
-}
-
-func TestMaxExecDepth(t *testing.T) {
-	if testing.Short() {
-		t.Skip("skipping in -short mode")
-	}
-	tmpl := Must(New("tmpl").Parse(`{{template "tmpl" .}}`))
-	err := tmpl.Execute(ioutil.Discard, nil)
-	got := "<nil>"
-	if err != nil {
-		got = err.Error()
-	}
-	const want = "exceeded maximum template depth"
-	if !strings.Contains(got, want) {
-		t.Errorf("got error %q; want %q", got, want)
-	}
-}
-
-func TestAddrOfIndex(t *testing.T) {
-	// golang.org/issue/14916.
-	// Before index worked on reflect.Values, the .String could not be
-	// found on the (incorrectly unaddressable) V value,
-	// in contrast to range, which worked fine.
-	// Also testing that passing a reflect.Value to tmpl.Execute works.
-	texts := []string{
-		`{{range .}}{{.String}}{{end}}`,
-		`{{with index . 0}}{{.String}}{{end}}`,
-	}
-	for _, text := range texts {
-		tmpl := Must(New("tmpl").Parse(text))
-		var buf bytes.Buffer
-		err := tmpl.Execute(&buf, reflect.ValueOf([]V{{1}}))
-		if err != nil {
-			t.Fatalf("%s: Execute: %v", text, err)
-		}
-		if buf.String() != "<1>" {
-			t.Fatalf("%s: template output = %q, want %q", text, &buf, "<1>")
-		}
-	}
-}
-
-func TestInterfaceValues(t *testing.T) {
-	// golang.org/issue/17714.
-	// Before index worked on reflect.Values, interface values
-	// were always implicitly promoted to the underlying value,
-	// except that nil interfaces were promoted to the zero reflect.Value.
-	// Eliminating a round trip to interface{} and back to reflect.Value
-	// eliminated this promotion, breaking these cases.
-	tests := []struct {
-		text string
-		out  string
-	}{
-		{`{{index .Nil 1}}`, "ERROR: index of untyped nil"},
-		{`{{index .Slice 2}}`, "2"},
-		{`{{index .Slice .Two}}`, "2"},
-		{`{{call .Nil 1}}`, "ERROR: call of nil"},
-		{`{{call .PlusOne 1}}`, "2"},
-		{`{{call .PlusOne .One}}`, "2"},
-		{`{{and (index .Slice 0) true}}`, "0"},
-		{`{{and .Zero true}}`, "0"},
-		{`{{and (index .Slice 1) false}}`, "false"},
-		{`{{and .One false}}`, "false"},
-		{`{{or (index .Slice 0) false}}`, "false"},
-		{`{{or .Zero false}}`, "false"},
-		{`{{or (index .Slice 1) true}}`, "1"},
-		{`{{or .One true}}`, "1"},
-		{`{{not (index .Slice 0)}}`, "true"},
-		{`{{not .Zero}}`, "true"},
-		{`{{not (index .Slice 1)}}`, "false"},
-		{`{{not .One}}`, "false"},
-		{`{{eq (index .Slice 0) .Zero}}`, "true"},
-		{`{{eq (index .Slice 1) .One}}`, "true"},
-		{`{{ne (index .Slice 0) .Zero}}`, "false"},
-		{`{{ne (index .Slice 1) .One}}`, "false"},
-		{`{{ge (index .Slice 0) .One}}`, "false"},
-		{`{{ge (index .Slice 1) .Zero}}`, "true"},
-		{`{{gt (index .Slice 0) .One}}`, "false"},
-		{`{{gt (index .Slice 1) .Zero}}`, "true"},
-		{`{{le (index .Slice 0) .One}}`, "true"},
-		{`{{le (index .Slice 1) .Zero}}`, "false"},
-		{`{{lt (index .Slice 0) .One}}`, "true"},
-		{`{{lt (index .Slice 1) .Zero}}`, "false"},
-	}
-
-	for _, tt := range tests {
-		tmpl := Must(New("tmpl").Parse(tt.text))
-		var buf bytes.Buffer
-		err := tmpl.Execute(&buf, map[string]interface{}{
-			"PlusOne": func(n int) int {
-				return n + 1
-			},
-			"Slice": []int{0, 1, 2, 3},
-			"One":   1,
-			"Two":   2,
-			"Nil":   nil,
-			"Zero":  0,
-		})
-		if strings.HasPrefix(tt.out, "ERROR:") {
-			e := strings.TrimSpace(strings.TrimPrefix(tt.out, "ERROR:"))
-			if err == nil || !strings.Contains(err.Error(), e) {
-				t.Errorf("%s: Execute: %v, want error %q", tt.text, err, e)
-			}
-			continue
-		}
-		if err != nil {
-			t.Errorf("%s: Execute: %v", tt.text, err)
-			continue
-		}
-		if buf.String() != tt.out {
-			t.Errorf("%s: template output = %q, want %q", tt.text, &buf, tt.out)
-		}
-	}
-}
-
-// Check that panics during calls are recovered and returned as errors.
-func TestExecutePanicDuringCall(t *testing.T) {
-	funcs := map[string]interface{}{
-		"doPanic": func() string {
-			panic("custom panic string")
-		},
-	}
-	tests := []struct {
-		name    string
-		input   string
-		data    interface{}
-		wantErr string
-	}{
-		{
-			"direct func call panics",
-			"{{doPanic}}", (*T)(nil),
-			`template: t:1:2: executing "t" at <doPanic>: error calling doPanic: custom panic string`,
-		},
-		{
-			"indirect func call panics",
-			"{{call doPanic}}", (*T)(nil),
-			`template: t:1:7: executing "t" at <doPanic>: error calling doPanic: custom panic string`,
-		},
-		{
-			"direct method call panics",
-			"{{.GetU}}", (*T)(nil),
-			`template: t:1:2: executing "t" at <.GetU>: error calling GetU: runtime error: invalid memory address or nil pointer dereference`,
-		},
-		{
-			"indirect method call panics",
-			"{{call .GetU}}", (*T)(nil),
-			`template: t:1:7: executing "t" at <.GetU>: error calling GetU: runtime error: invalid memory address or nil pointer dereference`,
-		},
-		{
-			"func field call panics",
-			"{{call .PanicFunc}}", tVal,
-			`template: t:1:2: executing "t" at <call .PanicFunc>: error calling call: test panic`,
-		},
-		{
-			"method call on nil interface",
-			"{{.NonEmptyInterfaceNil.Method0}}", tVal,
-			`template: t:1:23: executing "t" at <.NonEmptyInterfaceNil.Method0>: nil pointer evaluating template.I.Method0`,
-		},
-	}
-	for _, tc := range tests {
-		b := new(bytes.Buffer)
-		tmpl, err := New("t").Funcs(funcs).Parse(tc.input)
-		if err != nil {
-			t.Fatalf("parse error: %s", err)
-		}
-		err = tmpl.Execute(b, tc.data)
-		if err == nil {
-			t.Errorf("%s: expected error; got none", tc.name)
-		} else if !strings.Contains(err.Error(), tc.wantErr) {
-			if *debug {
-				fmt.Printf("%s: test execute error: %s\n", tc.name, err)
-			}
-			t.Errorf("%s: expected error:\n%s\ngot:\n%s", tc.name, tc.wantErr, err)
-		}
-	}
-}
-
-// Issue 31810. Check that a parenthesized first argument behaves properly.
-func TestIssue31810(t *testing.T) {
-	// A simple value with no arguments is fine.
-	var b bytes.Buffer
-	const text = "{{ (.)  }}"
-	tmpl, err := New("").Parse(text)
-	if err != nil {
-		t.Error(err)
-	}
-	err = tmpl.Execute(&b, "result")
-	if err != nil {
-		t.Error(err)
-	}
-	if b.String() != "result" {
-		t.Errorf("%s got %q, expected %q", text, b.String(), "result")
-	}
-
-	// Even a plain function fails - need to use call.
-	f := func() string { return "result" }
-	b.Reset()
-	err = tmpl.Execute(&b, f)
-	if err == nil {
-		t.Error("expected error with no call, got none")
-	}
-
-	// Works if the function is explicitly called.
-	const textCall = "{{ (call .)  }}"
-	tmpl, err = New("").Parse(textCall)
-	b.Reset()
-	err = tmpl.Execute(&b, f)
-	if err != nil {
-		t.Error(err)
-	}
-	if b.String() != "result" {
-		t.Errorf("%s got %q, expected %q", textCall, b.String(), "result")
-	}
-}
-
-// Issue 43065, range over send only channel
-func TestIssue43065(t *testing.T) {
-	var b bytes.Buffer
-	tmp := Must(New("").Parse(`{{range .}}{{end}}`))
-	ch := make(chan<- int)
-	err := tmp.Execute(&b, ch)
-	if err == nil {
-		t.Error("expected err got nil")
-	} else if !strings.Contains(err.Error(), "range over send-only channel") {
-		t.Errorf("%s", err)
-	}
-}
-
-// Issue 39807: data race in html/template & text/template
-func TestIssue39807(t *testing.T) {
-	var wg sync.WaitGroup
-
-	tplFoo, err := New("foo").Parse(`{{ template "bar" . }}`)
-	if err != nil {
-		t.Error(err)
-	}
-
-	tplBar, err := New("bar").Parse("bar")
-	if err != nil {
-		t.Error(err)
-	}
-
-	gofuncs := 10
-	numTemplates := 10
-
-	for i := 1; i <= gofuncs; i++ {
-		wg.Add(1)
-		go func() {
-			defer wg.Done()
-			for j := 0; j < numTemplates; j++ {
-				_, err := tplFoo.AddParseTree(tplBar.Name(), tplBar.Tree)
-				if err != nil {
-					t.Error(err)
-				}
-				err = tplFoo.Execute(ioutil.Discard, nil)
-				if err != nil {
-					t.Error(err)
-				}
-			}
-		}()
-	}
-
-	wg.Wait()
-}
diff --git a/go.dev/cmd/internal/text/template/funcs.go b/go.dev/cmd/internal/text/template/funcs.go
deleted file mode 100644
index 11e2e90..0000000
--- a/go.dev/cmd/internal/text/template/funcs.go
+++ /dev/null
@@ -1,753 +0,0 @@
-// Copyright 2011 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 template
-
-import (
-	"bytes"
-	"errors"
-	"fmt"
-	"io"
-	"net/url"
-	"reflect"
-	"strings"
-	"sync"
-	"unicode"
-	"unicode/utf8"
-)
-
-// FuncMap is the type of the map defining the mapping from names to functions.
-// Each function must have either a single return value, or two return values of
-// which the second has type error. In that case, if the second (error)
-// return value evaluates to non-nil during execution, execution terminates and
-// Execute returns that error.
-//
-// Errors returned by Execute wrap the underlying error; call errors.As to
-// uncover them.
-//
-// When template execution invokes a function with an argument list, that list
-// must be assignable to the function's parameter types. Functions meant to
-// apply to arguments of arbitrary type can use parameters of type interface{} or
-// of type reflect.Value. Similarly, functions meant to return a result of arbitrary
-// type can return interface{} or reflect.Value.
-type FuncMap map[string]interface{}
-
-// builtins returns the FuncMap.
-// It is not a global variable so the linker can dead code eliminate
-// more when this isn't called. See golang.org/issue/36021.
-// TODO: revert this back to a global map once golang.org/issue/2559 is fixed.
-func builtins() FuncMap {
-	return FuncMap{
-		"and":      and,
-		"call":     call,
-		"html":     HTMLEscaper,
-		"index":    index,
-		"slice":    slice,
-		"js":       JSEscaper,
-		"len":      length,
-		"not":      not,
-		"or":       or,
-		"print":    fmt.Sprint,
-		"printf":   fmt.Sprintf,
-		"println":  fmt.Sprintln,
-		"urlquery": URLQueryEscaper,
-
-		// Comparisons
-		"eq": eq, // ==
-		"ge": ge, // >=
-		"gt": gt, // >
-		"le": le, // <=
-		"lt": lt, // <
-		"ne": ne, // !=
-	}
-}
-
-var builtinFuncsOnce struct {
-	sync.Once
-	v map[string]reflect.Value
-}
-
-// builtinFuncsOnce lazily computes & caches the builtinFuncs map.
-// TODO: revert this back to a global map once golang.org/issue/2559 is fixed.
-func builtinFuncs() map[string]reflect.Value {
-	builtinFuncsOnce.Do(func() {
-		builtinFuncsOnce.v = createValueFuncs(builtins())
-	})
-	return builtinFuncsOnce.v
-}
-
-// createValueFuncs turns a FuncMap into a map[string]reflect.Value
-func createValueFuncs(funcMap FuncMap) map[string]reflect.Value {
-	m := make(map[string]reflect.Value)
-	addValueFuncs(m, funcMap)
-	return m
-}
-
-// addValueFuncs adds to values the functions in funcs, converting them to reflect.Values.
-func addValueFuncs(out map[string]reflect.Value, in FuncMap) {
-	for name, fn := range in {
-		if !goodName(name) {
-			panic(fmt.Errorf("function name %q is not a valid identifier", name))
-		}
-		v := reflect.ValueOf(fn)
-		if v.Kind() != reflect.Func {
-			panic("value for " + name + " not a function")
-		}
-		if !goodFunc(v.Type()) {
-			panic(fmt.Errorf("can't install method/function %q with %d results", name, v.Type().NumOut()))
-		}
-		out[name] = v
-	}
-}
-
-// addFuncs adds to values the functions in funcs. It does no checking of the input -
-// call addValueFuncs first.
-func addFuncs(out, in FuncMap) {
-	for name, fn := range in {
-		out[name] = fn
-	}
-}
-
-// goodFunc reports whether the function or method has the right result signature.
-func goodFunc(typ reflect.Type) bool {
-	// We allow functions with 1 result or 2 results where the second is an error.
-	switch {
-	case typ.NumOut() == 1:
-		return true
-	case typ.NumOut() == 2 && typ.Out(1) == errorType:
-		return true
-	}
-	return false
-}
-
-// goodName reports whether the function name is a valid identifier.
-func goodName(name string) bool {
-	if name == "" {
-		return false
-	}
-	for i, r := range name {
-		switch {
-		case r == '_':
-		case i == 0 && !unicode.IsLetter(r):
-			return false
-		case !unicode.IsLetter(r) && !unicode.IsDigit(r):
-			return false
-		}
-	}
-	return true
-}
-
-// findFunction looks for a function in the template, and global map.
-func findFunction(name string, tmpl *Template) (v reflect.Value, isBuiltin, ok bool) {
-	if tmpl != nil && tmpl.common != nil {
-		tmpl.muFuncs.RLock()
-		defer tmpl.muFuncs.RUnlock()
-		if fn := tmpl.execFuncs[name]; fn.IsValid() {
-			return fn, false, true
-		}
-	}
-	if fn := builtinFuncs()[name]; fn.IsValid() {
-		return fn, true, true
-	}
-	return reflect.Value{}, false, false
-}
-
-// prepareArg checks if value can be used as an argument of type argType, and
-// converts an invalid value to appropriate zero if possible.
-func prepareArg(value reflect.Value, argType reflect.Type) (reflect.Value, error) {
-	if !value.IsValid() {
-		if !canBeNil(argType) {
-			return reflect.Value{}, fmt.Errorf("value is nil; should be of type %s", argType)
-		}
-		value = reflect.Zero(argType)
-	}
-	if value.Type().AssignableTo(argType) {
-		return value, nil
-	}
-	if intLike(value.Kind()) && intLike(argType.Kind()) && value.Type().ConvertibleTo(argType) {
-		value = value.Convert(argType)
-		return value, nil
-	}
-	return reflect.Value{}, fmt.Errorf("value has type %s; should be %s", value.Type(), argType)
-}
-
-func intLike(typ reflect.Kind) bool {
-	switch typ {
-	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
-		return true
-	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
-		return true
-	}
-	return false
-}
-
-// indexArg checks if a reflect.Value can be used as an index, and converts it to int if possible.
-func indexArg(index reflect.Value, cap int) (int, error) {
-	var x int64
-	switch index.Kind() {
-	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
-		x = index.Int()
-	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
-		x = int64(index.Uint())
-	case reflect.Invalid:
-		return 0, fmt.Errorf("cannot index slice/array with nil")
-	default:
-		return 0, fmt.Errorf("cannot index slice/array with type %s", index.Type())
-	}
-	if x < 0 || int(x) < 0 || int(x) > cap {
-		return 0, fmt.Errorf("index out of range: %d", x)
-	}
-	return int(x), nil
-}
-
-// Indexing.
-
-// index returns the result of indexing its first argument by the following
-// arguments. Thus "index x 1 2 3" is, in Go syntax, x[1][2][3]. Each
-// indexed item must be a map, slice, or array.
-func index(item reflect.Value, indexes ...reflect.Value) (reflect.Value, error) {
-	item = indirectInterface(item)
-	if !item.IsValid() {
-		return reflect.Value{}, fmt.Errorf("index of untyped nil")
-	}
-	for _, index := range indexes {
-		index = indirectInterface(index)
-		var isNil bool
-		if item, isNil = indirect(item); isNil {
-			return reflect.Value{}, fmt.Errorf("index of nil pointer")
-		}
-		switch item.Kind() {
-		case reflect.Array, reflect.Slice, reflect.String:
-			x, err := indexArg(index, item.Len())
-			if err != nil {
-				return reflect.Value{}, err
-			}
-			item = item.Index(x)
-		case reflect.Map:
-			index, err := prepareArg(index, item.Type().Key())
-			if err != nil {
-				return reflect.Value{}, err
-			}
-			if x := item.MapIndex(index); x.IsValid() {
-				item = x
-			} else {
-				item = reflect.Zero(item.Type().Elem())
-			}
-		case reflect.Invalid:
-			// the loop holds invariant: item.IsValid()
-			panic("unreachable")
-		default:
-			return reflect.Value{}, fmt.Errorf("can't index item of type %s", item.Type())
-		}
-	}
-	return item, nil
-}
-
-// Slicing.
-
-// slice returns the result of slicing its first argument by the remaining
-// arguments. Thus "slice x 1 2" is, in Go syntax, x[1:2], while "slice x"
-// is x[:], "slice x 1" is x[1:], and "slice x 1 2 3" is x[1:2:3]. The first
-// argument must be a string, slice, or array.
-func slice(item reflect.Value, indexes ...reflect.Value) (reflect.Value, error) {
-	item = indirectInterface(item)
-	if !item.IsValid() {
-		return reflect.Value{}, fmt.Errorf("slice of untyped nil")
-	}
-	if len(indexes) > 3 {
-		return reflect.Value{}, fmt.Errorf("too many slice indexes: %d", len(indexes))
-	}
-	var cap int
-	switch item.Kind() {
-	case reflect.String:
-		if len(indexes) == 3 {
-			return reflect.Value{}, fmt.Errorf("cannot 3-index slice a string")
-		}
-		cap = item.Len()
-	case reflect.Array, reflect.Slice:
-		cap = item.Cap()
-	default:
-		return reflect.Value{}, fmt.Errorf("can't slice item of type %s", item.Type())
-	}
-	// set default values for cases item[:], item[i:].
-	idx := [3]int{0, item.Len()}
-	for i, index := range indexes {
-		x, err := indexArg(index, cap)
-		if err != nil {
-			return reflect.Value{}, err
-		}
-		idx[i] = x
-	}
-	// given item[i:j], make sure i <= j.
-	if idx[0] > idx[1] {
-		return reflect.Value{}, fmt.Errorf("invalid slice index: %d > %d", idx[0], idx[1])
-	}
-	if len(indexes) < 3 {
-		return item.Slice(idx[0], idx[1]), nil
-	}
-	// given item[i:j:k], make sure i <= j <= k.
-	if idx[1] > idx[2] {
-		return reflect.Value{}, fmt.Errorf("invalid slice index: %d > %d", idx[1], idx[2])
-	}
-	return item.Slice3(idx[0], idx[1], idx[2]), nil
-}
-
-// Length
-
-// length returns the length of the item, with an error if it has no defined length.
-func length(item reflect.Value) (int, error) {
-	item, isNil := indirect(item)
-	if isNil {
-		return 0, fmt.Errorf("len of nil pointer")
-	}
-	switch item.Kind() {
-	case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice, reflect.String:
-		return item.Len(), nil
-	}
-	return 0, fmt.Errorf("len of type %s", item.Type())
-}
-
-// Function invocation
-
-// call returns the result of evaluating the first argument as a function.
-// The function must return 1 result, or 2 results, the second of which is an error.
-func call(fn reflect.Value, args ...reflect.Value) (reflect.Value, error) {
-	fn = indirectInterface(fn)
-	if !fn.IsValid() {
-		return reflect.Value{}, fmt.Errorf("call of nil")
-	}
-	typ := fn.Type()
-	if typ.Kind() != reflect.Func {
-		return reflect.Value{}, fmt.Errorf("non-function of type %s", typ)
-	}
-	if !goodFunc(typ) {
-		return reflect.Value{}, fmt.Errorf("function called with %d args; should be 1 or 2", typ.NumOut())
-	}
-	numIn := typ.NumIn()
-	var dddType reflect.Type
-	if typ.IsVariadic() {
-		if len(args) < numIn-1 {
-			return reflect.Value{}, fmt.Errorf("wrong number of args: got %d want at least %d", len(args), numIn-1)
-		}
-		dddType = typ.In(numIn - 1).Elem()
-	} else {
-		if len(args) != numIn {
-			return reflect.Value{}, fmt.Errorf("wrong number of args: got %d want %d", len(args), numIn)
-		}
-	}
-	argv := make([]reflect.Value, len(args))
-	for i, arg := range args {
-		arg = indirectInterface(arg)
-		// Compute the expected type. Clumsy because of variadics.
-		argType := dddType
-		if !typ.IsVariadic() || i < numIn-1 {
-			argType = typ.In(i)
-		}
-
-		var err error
-		if argv[i], err = prepareArg(arg, argType); err != nil {
-			return reflect.Value{}, fmt.Errorf("arg %d: %w", i, err)
-		}
-	}
-	return safeCall(fn, argv)
-}
-
-// safeCall runs fun.Call(args), and returns the resulting value and error, if
-// any. If the call panics, the panic value is returned as an error.
-func safeCall(fun reflect.Value, args []reflect.Value) (val reflect.Value, err error) {
-	defer func() {
-		if r := recover(); r != nil {
-			if e, ok := r.(error); ok {
-				err = e
-			} else {
-				err = fmt.Errorf("%v", r)
-			}
-		}
-	}()
-	ret := fun.Call(args)
-	if len(ret) == 2 && !ret[1].IsNil() {
-		return ret[0], ret[1].Interface().(error)
-	}
-	return ret[0], nil
-}
-
-// Boolean logic.
-
-func truth(arg reflect.Value) bool {
-	t, _ := isTrue(indirectInterface(arg))
-	return t
-}
-
-// and computes the Boolean AND of its arguments, returning
-// the first false argument it encounters, or the last argument.
-func and(arg0 reflect.Value, args ...reflect.Value) reflect.Value {
-	panic("unreachable") // implemented as a special case in evalCall
-}
-
-// or computes the Boolean OR of its arguments, returning
-// the first true argument it encounters, or the last argument.
-func or(arg0 reflect.Value, args ...reflect.Value) reflect.Value {
-	panic("unreachable") // implemented as a special case in evalCall
-}
-
-// not returns the Boolean negation of its argument.
-func not(arg reflect.Value) bool {
-	return !truth(arg)
-}
-
-// Comparison.
-
-// TODO: Perhaps allow comparison between signed and unsigned integers.
-
-var (
-	errBadComparisonType = errors.New("invalid type for comparison")
-	errBadComparison     = errors.New("incompatible types for comparison")
-	errNoComparison      = errors.New("missing argument for comparison")
-)
-
-type kind int
-
-const (
-	invalidKind kind = iota
-	boolKind
-	complexKind
-	intKind
-	floatKind
-	stringKind
-	uintKind
-)
-
-func basicKind(v reflect.Value) (kind, error) {
-	switch v.Kind() {
-	case reflect.Bool:
-		return boolKind, nil
-	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
-		return intKind, nil
-	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
-		return uintKind, nil
-	case reflect.Float32, reflect.Float64:
-		return floatKind, nil
-	case reflect.Complex64, reflect.Complex128:
-		return complexKind, nil
-	case reflect.String:
-		return stringKind, nil
-	}
-	return invalidKind, errBadComparisonType
-}
-
-// eq evaluates the comparison a == b || a == c || ...
-func eq(arg1 reflect.Value, arg2 ...reflect.Value) (bool, error) {
-	arg1 = indirectInterface(arg1)
-	if arg1 != zero {
-		if t1 := arg1.Type(); !t1.Comparable() {
-			return false, fmt.Errorf("uncomparable type %s: %v", t1, arg1)
-		}
-	}
-	if len(arg2) == 0 {
-		return false, errNoComparison
-	}
-	k1, _ := basicKind(arg1)
-	for _, arg := range arg2 {
-		arg = indirectInterface(arg)
-		k2, _ := basicKind(arg)
-		truth := false
-		if k1 != k2 {
-			// Special case: Can compare integer values regardless of type's sign.
-			switch {
-			case k1 == intKind && k2 == uintKind:
-				truth = arg1.Int() >= 0 && uint64(arg1.Int()) == arg.Uint()
-			case k1 == uintKind && k2 == intKind:
-				truth = arg.Int() >= 0 && arg1.Uint() == uint64(arg.Int())
-			default:
-				if arg1 != zero && arg != zero {
-					return false, errBadComparison
-				}
-			}
-		} else {
-			switch k1 {
-			case boolKind:
-				truth = arg1.Bool() == arg.Bool()
-			case complexKind:
-				truth = arg1.Complex() == arg.Complex()
-			case floatKind:
-				truth = arg1.Float() == arg.Float()
-			case intKind:
-				truth = arg1.Int() == arg.Int()
-			case stringKind:
-				truth = arg1.String() == arg.String()
-			case uintKind:
-				truth = arg1.Uint() == arg.Uint()
-			default:
-				if arg == zero || arg1 == zero {
-					truth = arg1 == arg
-				} else {
-					if t2 := arg.Type(); !t2.Comparable() {
-						return false, fmt.Errorf("uncomparable type %s: %v", t2, arg)
-					}
-					truth = arg1.Interface() == arg.Interface()
-				}
-			}
-		}
-		if truth {
-			return true, nil
-		}
-	}
-	return false, nil
-}
-
-// ne evaluates the comparison a != b.
-func ne(arg1, arg2 reflect.Value) (bool, error) {
-	// != is the inverse of ==.
-	equal, err := eq(arg1, arg2)
-	return !equal, err
-}
-
-// lt evaluates the comparison a < b.
-func lt(arg1, arg2 reflect.Value) (bool, error) {
-	arg1 = indirectInterface(arg1)
-	k1, err := basicKind(arg1)
-	if err != nil {
-		return false, err
-	}
-	arg2 = indirectInterface(arg2)
-	k2, err := basicKind(arg2)
-	if err != nil {
-		return false, err
-	}
-	truth := false
-	if k1 != k2 {
-		// Special case: Can compare integer values regardless of type's sign.
-		switch {
-		case k1 == intKind && k2 == uintKind:
-			truth = arg1.Int() < 0 || uint64(arg1.Int()) < arg2.Uint()
-		case k1 == uintKind && k2 == intKind:
-			truth = arg2.Int() >= 0 && arg1.Uint() < uint64(arg2.Int())
-		default:
-			return false, errBadComparison
-		}
-	} else {
-		switch k1 {
-		case boolKind, complexKind:
-			return false, errBadComparisonType
-		case floatKind:
-			truth = arg1.Float() < arg2.Float()
-		case intKind:
-			truth = arg1.Int() < arg2.Int()
-		case stringKind:
-			truth = arg1.String() < arg2.String()
-		case uintKind:
-			truth = arg1.Uint() < arg2.Uint()
-		default:
-			panic("invalid kind")
-		}
-	}
-	return truth, nil
-}
-
-// le evaluates the comparison <= b.
-func le(arg1, arg2 reflect.Value) (bool, error) {
-	// <= is < or ==.
-	lessThan, err := lt(arg1, arg2)
-	if lessThan || err != nil {
-		return lessThan, err
-	}
-	return eq(arg1, arg2)
-}
-
-// gt evaluates the comparison a > b.
-func gt(arg1, arg2 reflect.Value) (bool, error) {
-	// > is the inverse of <=.
-	lessOrEqual, err := le(arg1, arg2)
-	if err != nil {
-		return false, err
-	}
-	return !lessOrEqual, nil
-}
-
-// ge evaluates the comparison a >= b.
-func ge(arg1, arg2 reflect.Value) (bool, error) {
-	// >= is the inverse of <.
-	lessThan, err := lt(arg1, arg2)
-	if err != nil {
-		return false, err
-	}
-	return !lessThan, nil
-}
-
-// HTML escaping.
-
-var (
-	htmlQuot = []byte("&#34;") // shorter than "&quot;"
-	htmlApos = []byte("&#39;") // shorter than "&apos;" and apos was not in HTML until HTML5
-	htmlAmp  = []byte("&amp;")
-	htmlLt   = []byte("&lt;")
-	htmlGt   = []byte("&gt;")
-	htmlNull = []byte("\uFFFD")
-)
-
-// HTMLEscape writes to w the escaped HTML equivalent of the plain text data b.
-func HTMLEscape(w io.Writer, b []byte) {
-	last := 0
-	for i, c := range b {
-		var html []byte
-		switch c {
-		case '\000':
-			html = htmlNull
-		case '"':
-			html = htmlQuot
-		case '\'':
-			html = htmlApos
-		case '&':
-			html = htmlAmp
-		case '<':
-			html = htmlLt
-		case '>':
-			html = htmlGt
-		default:
-			continue
-		}
-		w.Write(b[last:i])
-		w.Write(html)
-		last = i + 1
-	}
-	w.Write(b[last:])
-}
-
-// HTMLEscapeString returns the escaped HTML equivalent of the plain text data s.
-func HTMLEscapeString(s string) string {
-	// Avoid allocation if we can.
-	if !strings.ContainsAny(s, "'\"&<>\000") {
-		return s
-	}
-	var b bytes.Buffer
-	HTMLEscape(&b, []byte(s))
-	return b.String()
-}
-
-// HTMLEscaper returns the escaped HTML equivalent of the textual
-// representation of its arguments.
-func HTMLEscaper(args ...interface{}) string {
-	return HTMLEscapeString(evalArgs(args))
-}
-
-// JavaScript escaping.
-
-var (
-	jsLowUni = []byte(`\u00`)
-	hex      = []byte("0123456789ABCDEF")
-
-	jsBackslash = []byte(`\\`)
-	jsApos      = []byte(`\'`)
-	jsQuot      = []byte(`\"`)
-	jsLt        = []byte(`\u003C`)
-	jsGt        = []byte(`\u003E`)
-	jsAmp       = []byte(`\u0026`)
-	jsEq        = []byte(`\u003D`)
-)
-
-// JSEscape writes to w the escaped JavaScript equivalent of the plain text data b.
-func JSEscape(w io.Writer, b []byte) {
-	last := 0
-	for i := 0; i < len(b); i++ {
-		c := b[i]
-
-		if !jsIsSpecial(rune(c)) {
-			// fast path: nothing to do
-			continue
-		}
-		w.Write(b[last:i])
-
-		if c < utf8.RuneSelf {
-			// Quotes, slashes and angle brackets get quoted.
-			// Control characters get written as \u00XX.
-			switch c {
-			case '\\':
-				w.Write(jsBackslash)
-			case '\'':
-				w.Write(jsApos)
-			case '"':
-				w.Write(jsQuot)
-			case '<':
-				w.Write(jsLt)
-			case '>':
-				w.Write(jsGt)
-			case '&':
-				w.Write(jsAmp)
-			case '=':
-				w.Write(jsEq)
-			default:
-				w.Write(jsLowUni)
-				t, b := c>>4, c&0x0f
-				w.Write(hex[t : t+1])
-				w.Write(hex[b : b+1])
-			}
-		} else {
-			// Unicode rune.
-			r, size := utf8.DecodeRune(b[i:])
-			if unicode.IsPrint(r) {
-				w.Write(b[i : i+size])
-			} else {
-				fmt.Fprintf(w, "\\u%04X", r)
-			}
-			i += size - 1
-		}
-		last = i + 1
-	}
-	w.Write(b[last:])
-}
-
-// JSEscapeString returns the escaped JavaScript equivalent of the plain text data s.
-func JSEscapeString(s string) string {
-	// Avoid allocation if we can.
-	if strings.IndexFunc(s, jsIsSpecial) < 0 {
-		return s
-	}
-	var b bytes.Buffer
-	JSEscape(&b, []byte(s))
-	return b.String()
-}
-
-func jsIsSpecial(r rune) bool {
-	switch r {
-	case '\\', '\'', '"', '<', '>', '&', '=':
-		return true
-	}
-	return r < ' ' || utf8.RuneSelf <= r
-}
-
-// JSEscaper returns the escaped JavaScript equivalent of the textual
-// representation of its arguments.
-func JSEscaper(args ...interface{}) string {
-	return JSEscapeString(evalArgs(args))
-}
-
-// URLQueryEscaper returns the escaped value of the textual representation of
-// its arguments in a form suitable for embedding in a URL query.
-func URLQueryEscaper(args ...interface{}) string {
-	return url.QueryEscape(evalArgs(args))
-}
-
-// evalArgs formats the list of arguments into a string. It is therefore equivalent to
-//	fmt.Sprint(args...)
-// except that each argument is indirected (if a pointer), as required,
-// using the same rules as the default string evaluation during template
-// execution.
-func evalArgs(args []interface{}) string {
-	ok := false
-	var s string
-	// Fast path for simple common case.
-	if len(args) == 1 {
-		s, ok = args[0].(string)
-	}
-	if !ok {
-		for i, arg := range args {
-			a, ok := printableValue(reflect.ValueOf(arg))
-			if ok {
-				args[i] = a
-			} // else let fmt do its thing
-		}
-		s = fmt.Sprint(args...)
-	}
-	return s
-}
diff --git a/go.dev/cmd/internal/text/template/funcs.go.save b/go.dev/cmd/internal/text/template/funcs.go.save
deleted file mode 100644
index c3f6d47..0000000
--- a/go.dev/cmd/internal/text/template/funcs.go.save
+++ /dev/null
@@ -1,771 +0,0 @@
-// Copyright 2011 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 template
-
-import (
-	"bytes"
-	"errors"
-	"fmt"
-	"io"
-	"net/url"
-	"reflect"
-	"strings"
-	"sync"
-	"unicode"
-	"unicode/utf8"
-)
-
-// FuncMap is the type of the map defining the mapping from names to functions.
-// Each function must have either a single return value, or two return values of
-// which the second has type error. In that case, if the second (error)
-// return value evaluates to non-nil during execution, execution terminates and
-// Execute returns that error.
-//
-// Errors returned by Execute wrap the underlying error; call errors.As to
-// uncover them.
-//
-// When template execution invokes a function with an argument list, that list
-// must be assignable to the function's parameter types. Functions meant to
-// apply to arguments of arbitrary type can use parameters of type interface{} or
-// of type reflect.Value. Similarly, functions meant to return a result of arbitrary
-// type can return interface{} or reflect.Value.
-type FuncMap map[string]interface{}
-
-// builtins returns the FuncMap.
-// It is not a global variable so the linker can dead code eliminate
-// more when this isn't called. See golang.org/issue/36021.
-// TODO: revert this back to a global map once golang.org/issue/2559 is fixed.
-func builtins() FuncMap {
-	return FuncMap{
-		"and":      and,
-		"call":     call,
-		"html":     HTMLEscaper,
-		"index":    index,
-		"slice":    slice,
-		"js":       JSEscaper,
-		"len":      length,
-		"not":      not,
-		"or":       or,
-		"print":    fmt.Sprint,
-		"printf":   fmt.Sprintf,
-		"println":  fmt.Sprintln,
-		"urlquery": URLQueryEscaper,
-
-		// Comparisons
-		"eq": eq, // ==
-		"ge": ge, // >=
-		"gt": gt, // >
-		"le": le, // <=
-		"lt": lt, // <
-		"ne": ne, // !=
-	}
-}
-
-var builtinFuncsOnce struct {
-	sync.Once
-	v map[string]reflect.Value
-}
-
-// builtinFuncsOnce lazily computes & caches the builtinFuncs map.
-// TODO: revert this back to a global map once golang.org/issue/2559 is fixed.
-func builtinFuncs() map[string]reflect.Value {
-	builtinFuncsOnce.Do(func() {
-		builtinFuncsOnce.v = createValueFuncs(builtins())
-	})
-	return builtinFuncsOnce.v
-}
-
-// createValueFuncs turns a FuncMap into a map[string]reflect.Value
-func createValueFuncs(funcMap FuncMap) map[string]reflect.Value {
-	m := make(map[string]reflect.Value)
-	addValueFuncs(m, funcMap)
-	return m
-}
-
-// addValueFuncs adds to values the functions in funcs, converting them to reflect.Values.
-func addValueFuncs(out map[string]reflect.Value, in FuncMap) {
-	for name, fn := range in {
-		if !goodName(name) {
-			panic(fmt.Errorf("function name %q is not a valid identifier", name))
-		}
-		v := reflect.ValueOf(fn)
-		if v.Kind() != reflect.Func {
-			panic("value for " + name + " not a function")
-		}
-		if !goodFunc(v.Type()) {
-			panic(fmt.Errorf("can't install method/function %q with %d results", name, v.Type().NumOut()))
-		}
-		out[name] = v
-	}
-}
-
-// addFuncs adds to values the functions in funcs. It does no checking of the input -
-// call addValueFuncs first.
-func addFuncs(out, in FuncMap) {
-	for name, fn := range in {
-		out[name] = fn
-	}
-}
-
-// goodFunc reports whether the function or method has the right result signature.
-func goodFunc(typ reflect.Type) bool {
-	// We allow functions with 1 result or 2 results where the second is an error.
-	switch {
-	case typ.NumOut() == 1:
-		return true
-	case typ.NumOut() == 2 && typ.Out(1) == errorType:
-		return true
-	}
-	return false
-}
-
-// goodName reports whether the function name is a valid identifier.
-func goodName(name string) bool {
-	if name == "" {
-		return false
-	}
-	for i, r := range name {
-		switch {
-		case r == '_':
-		case i == 0 && !unicode.IsLetter(r):
-			return false
-		case !unicode.IsLetter(r) && !unicode.IsDigit(r):
-			return false
-		}
-	}
-	return true
-}
-
-// findFunction looks for a function in the template, and global map.
-func findFunction(name string, tmpl *Template) (reflect.Value, bool) {
-	if tmpl != nil && tmpl.common != nil {
-		tmpl.muFuncs.RLock()
-		defer tmpl.muFuncs.RUnlock()
-		if fn := tmpl.execFuncs[name]; fn.IsValid() {
-			return fn, true
-		}
-	}
-	if fn := builtinFuncs()[name]; fn.IsValid() {
-		return fn, true
-	}
-	return reflect.Value{}, false
-}
-
-// prepareArg checks if value can be used as an argument of type argType, and
-// converts an invalid value to appropriate zero if possible.
-func prepareArg(value reflect.Value, argType reflect.Type) (reflect.Value, error) {
-	if !value.IsValid() {
-		if !canBeNil(argType) {
-			return reflect.Value{}, fmt.Errorf("value is nil; should be of type %s", argType)
-		}
-		value = reflect.Zero(argType)
-	}
-	if value.Type().AssignableTo(argType) {
-		return value, nil
-	}
-	if intLike(value.Kind()) && intLike(argType.Kind()) && value.Type().ConvertibleTo(argType) {
-		value = value.Convert(argType)
-		return value, nil
-	}
-	return reflect.Value{}, fmt.Errorf("value has type %s; should be %s", value.Type(), argType)
-}
-
-func intLike(typ reflect.Kind) bool {
-	switch typ {
-	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
-		return true
-	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
-		return true
-	}
-	return false
-}
-
-// indexArg checks if a reflect.Value can be used as an index, and converts it to int if possible.
-func indexArg(index reflect.Value, cap int) (int, error) {
-	var x int64
-	switch index.Kind() {
-	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
-		x = index.Int()
-	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
-		x = int64(index.Uint())
-	case reflect.Invalid:
-		return 0, fmt.Errorf("cannot index slice/array with nil")
-	default:
-		return 0, fmt.Errorf("cannot index slice/array with type %s", index.Type())
-	}
-	if x < 0 || int(x) < 0 || int(x) > cap {
-		return 0, fmt.Errorf("index out of range: %d", x)
-	}
-	return int(x), nil
-}
-
-// Indexing.
-
-// index returns the result of indexing its first argument by the following
-// arguments. Thus "index x 1 2 3" is, in Go syntax, x[1][2][3]. Each
-// indexed item must be a map, slice, or array.
-func index(item reflect.Value, indexes ...reflect.Value) (reflect.Value, error) {
-	item = indirectInterface(item)
-	if !item.IsValid() {
-		return reflect.Value{}, fmt.Errorf("index of untyped nil")
-	}
-	for _, index := range indexes {
-		index = indirectInterface(index)
-		var isNil bool
-		if item, isNil = indirect(item); isNil {
-			return reflect.Value{}, fmt.Errorf("index of nil pointer")
-		}
-		switch item.Kind() {
-		case reflect.Array, reflect.Slice, reflect.String:
-			x, err := indexArg(index, item.Len())
-			if err != nil {
-				return reflect.Value{}, err
-			}
-			item = item.Index(x)
-		case reflect.Map:
-			index, err := prepareArg(index, item.Type().Key())
-			if err != nil {
-				return reflect.Value{}, err
-			}
-			if x := item.MapIndex(index); x.IsValid() {
-				item = x
-			} else {
-				item = reflect.Zero(item.Type().Elem())
-			}
-		case reflect.Invalid:
-			// the loop holds invariant: item.IsValid()
-			panic("unreachable")
-		default:
-			return reflect.Value{}, fmt.Errorf("can't index item of type %s", item.Type())
-		}
-	}
-	return item, nil
-}
-
-// Slicing.
-
-// slice returns the result of slicing its first argument by the remaining
-// arguments. Thus "slice x 1 2" is, in Go syntax, x[1:2], while "slice x"
-// is x[:], "slice x 1" is x[1:], and "slice x 1 2 3" is x[1:2:3]. The first
-// argument must be a string, slice, or array.
-func slice(item reflect.Value, indexes ...reflect.Value) (reflect.Value, error) {
-	item = indirectInterface(item)
-	if !item.IsValid() {
-		return reflect.Value{}, fmt.Errorf("slice of untyped nil")
-	}
-	if len(indexes) > 3 {
-		return reflect.Value{}, fmt.Errorf("too many slice indexes: %d", len(indexes))
-	}
-	var cap int
-	switch item.Kind() {
-	case reflect.String:
-		if len(indexes) == 3 {
-			return reflect.Value{}, fmt.Errorf("cannot 3-index slice a string")
-		}
-		cap = item.Len()
-	case reflect.Array, reflect.Slice:
-		cap = item.Cap()
-	default:
-		return reflect.Value{}, fmt.Errorf("can't slice item of type %s", item.Type())
-	}
-	// set default values for cases item[:], item[i:].
-	idx := [3]int{0, item.Len()}
-	for i, index := range indexes {
-		x, err := indexArg(index, cap)
-		if err != nil {
-			return reflect.Value{}, err
-		}
-		idx[i] = x
-	}
-	// given item[i:j], make sure i <= j.
-	if idx[0] > idx[1] {
-		return reflect.Value{}, fmt.Errorf("invalid slice index: %d > %d", idx[0], idx[1])
-	}
-	if len(indexes) < 3 {
-		return item.Slice(idx[0], idx[1]), nil
-	}
-	// given item[i:j:k], make sure i <= j <= k.
-	if idx[1] > idx[2] {
-		return reflect.Value{}, fmt.Errorf("invalid slice index: %d > %d", idx[1], idx[2])
-	}
-	return item.Slice3(idx[0], idx[1], idx[2]), nil
-}
-
-// Length
-
-// length returns the length of the item, with an error if it has no defined length.
-func length(item reflect.Value) (int, error) {
-	item, isNil := indirect(item)
-	if isNil {
-		return 0, fmt.Errorf("len of nil pointer")
-	}
-	switch item.Kind() {
-	case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice, reflect.String:
-		return item.Len(), nil
-	}
-	return 0, fmt.Errorf("len of type %s", item.Type())
-}
-
-// Function invocation
-
-// call returns the result of evaluating the first argument as a function.
-// The function must return 1 result, or 2 results, the second of which is an error.
-func call(fn reflect.Value, args ...reflect.Value) (reflect.Value, error) {
-	fn = indirectInterface(fn)
-	if !fn.IsValid() {
-		return reflect.Value{}, fmt.Errorf("call of nil")
-	}
-	typ := fn.Type()
-	if typ.Kind() != reflect.Func {
-		return reflect.Value{}, fmt.Errorf("non-function of type %s", typ)
-	}
-	if !goodFunc(typ) {
-		return reflect.Value{}, fmt.Errorf("function called with %d args; should be 1 or 2", typ.NumOut())
-	}
-	numIn := typ.NumIn()
-	var dddType reflect.Type
-	if typ.IsVariadic() {
-		if len(args) < numIn-1 {
-			return reflect.Value{}, fmt.Errorf("wrong number of args: got %d want at least %d", len(args), numIn-1)
-		}
-		dddType = typ.In(numIn - 1).Elem()
-	} else {
-		if len(args) != numIn {
-			return reflect.Value{}, fmt.Errorf("wrong number of args: got %d want %d", len(args), numIn)
-		}
-	}
-	argv := make([]reflect.Value, len(args))
-	for i, arg := range args {
-		arg = indirectInterface(arg)
-		// Compute the expected type. Clumsy because of variadics.
-		argType := dddType
-		if !typ.IsVariadic() || i < numIn-1 {
-			argType = typ.In(i)
-		}
-
-		var err error
-		if argv[i], err = prepareArg(arg, argType); err != nil {
-			return reflect.Value{}, fmt.Errorf("arg %d: %w", i, err)
-		}
-	}
-	return safeCall(fn, argv)
-}
-
-// safeCall runs fun.Call(args), and returns the resulting value and error, if
-// any. If the call panics, the panic value is returned as an error.
-func safeCall(fun reflect.Value, args []reflect.Value) (val reflect.Value, err error) {
-	defer func() {
-		if r := recover(); r != nil {
-			if e, ok := r.(error); ok {
-				err = e
-			} else {
-				err = fmt.Errorf("%v", r)
-			}
-		}
-	}()
-	ret := fun.Call(args)
-	if len(ret) == 2 && !ret[1].IsNil() {
-		return ret[0], ret[1].Interface().(error)
-	}
-	return ret[0], nil
-}
-
-// Boolean logic.
-
-func truth(arg reflect.Value) bool {
-	t, _ := isTrue(indirectInterface(arg))
-	return t
-}
-
-// and computes the Boolean AND of its arguments, returning
-// the first false argument it encounters, or the last argument.
-func and(arg0 reflect.Value, args ...reflect.Value) reflect.Value {
-	if !truth(arg0) {
-		return arg0
-	}
-	for i := range args {
-		arg0 = args[i]
-		if !truth(arg0) {
-			break
-		}
-	}
-	return arg0
-}
-
-// or computes the Boolean OR of its arguments, returning
-// the first true argument it encounters, or the last argument.
-func or(arg0 reflect.Value, args ...reflect.Value) reflect.Value {
-	if truth(arg0) {
-		return arg0
-	}
-	for i := range args {
-		arg0 = args[i]
-		if truth(arg0) {
-			break
-		}
-	}
-	return arg0
-}
-
-// not returns the Boolean negation of its argument.
-func not(arg reflect.Value) bool {
-	return !truth(arg)
-}
-
-// Comparison.
-
-// TODO: Perhaps allow comparison between signed and unsigned integers.
-
-var (
-	errBadComparisonType = errors.New("invalid type for comparison")
-	errBadComparison     = errors.New("incompatible types for comparison")
-	errNoComparison      = errors.New("missing argument for comparison")
-)
-
-type kind int
-
-const (
-	invalidKind kind = iota
-	boolKind
-	complexKind
-	intKind
-	floatKind
-	stringKind
-	uintKind
-)
-
-func basicKind(v reflect.Value) (kind, error) {
-	switch v.Kind() {
-	case reflect.Bool:
-		return boolKind, nil
-	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
-		return intKind, nil
-	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
-		return uintKind, nil
-	case reflect.Float32, reflect.Float64:
-		return floatKind, nil
-	case reflect.Complex64, reflect.Complex128:
-		return complexKind, nil
-	case reflect.String:
-		return stringKind, nil
-	}
-	return invalidKind, errBadComparisonType
-}
-
-// eq evaluates the comparison a == b || a == c || ...
-func eq(arg1 reflect.Value, arg2 ...reflect.Value) (bool, error) {
-	arg1 = indirectInterface(arg1)
-	if arg1 != zero {
-		if t1 := arg1.Type(); !t1.Comparable() {
-			return false, fmt.Errorf("uncomparable type %s: %v", t1, arg1)
-		}
-	}
-	if len(arg2) == 0 {
-		return false, errNoComparison
-	}
-	k1, _ := basicKind(arg1)
-	for _, arg := range arg2 {
-		arg = indirectInterface(arg)
-		k2, _ := basicKind(arg)
-		truth := false
-		if k1 != k2 {
-			// Special case: Can compare integer values regardless of type's sign.
-			switch {
-			case k1 == intKind && k2 == uintKind:
-				truth = arg1.Int() >= 0 && uint64(arg1.Int()) == arg.Uint()
-			case k1 == uintKind && k2 == intKind:
-				truth = arg.Int() >= 0 && arg1.Uint() == uint64(arg.Int())
-			default:
-				if arg1 != zero && arg != zero {
-					return false, errBadComparison
-				}
-			}
-		} else {
-			switch k1 {
-			case boolKind:
-				truth = arg1.Bool() == arg.Bool()
-			case complexKind:
-				truth = arg1.Complex() == arg.Complex()
-			case floatKind:
-				truth = arg1.Float() == arg.Float()
-			case intKind:
-				truth = arg1.Int() == arg.Int()
-			case stringKind:
-				truth = arg1.String() == arg.String()
-			case uintKind:
-				truth = arg1.Uint() == arg.Uint()
-			default:
-				if arg == zero {
-					truth = arg1 == arg
-				} else {
-					if t2 := arg.Type(); !t2.Comparable() {
-						return false, fmt.Errorf("uncomparable type %s: %v", t2, arg)
-					}
-					truth = arg1.Interface() == arg.Interface()
-				}
-			}
-		}
-		if truth {
-			return true, nil
-		}
-	}
-	return false, nil
-}
-
-// ne evaluates the comparison a != b.
-func ne(arg1, arg2 reflect.Value) (bool, error) {
-	// != is the inverse of ==.
-	equal, err := eq(arg1, arg2)
-	return !equal, err
-}
-
-// lt evaluates the comparison a < b.
-func lt(arg1, arg2 reflect.Value) (bool, error) {
-	arg1 = indirectInterface(arg1)
-	k1, err := basicKind(arg1)
-	if err != nil {
-		return false, err
-	}
-	arg2 = indirectInterface(arg2)
-	k2, err := basicKind(arg2)
-	if err != nil {
-		return false, err
-	}
-	truth := false
-	if k1 != k2 {
-		// Special case: Can compare integer values regardless of type's sign.
-		switch {
-		case k1 == intKind && k2 == uintKind:
-			truth = arg1.Int() < 0 || uint64(arg1.Int()) < arg2.Uint()
-		case k1 == uintKind && k2 == intKind:
-			truth = arg2.Int() >= 0 && arg1.Uint() < uint64(arg2.Int())
-		default:
-			return false, errBadComparison
-		}
-	} else {
-		switch k1 {
-		case boolKind, complexKind:
-			return false, errBadComparisonType
-		case floatKind:
-			truth = arg1.Float() < arg2.Float()
-		case intKind:
-			truth = arg1.Int() < arg2.Int()
-		case stringKind:
-			truth = arg1.String() < arg2.String()
-		case uintKind:
-			truth = arg1.Uint() < arg2.Uint()
-		default:
-			panic("invalid kind")
-		}
-	}
-	return truth, nil
-}
-
-// le evaluates the comparison <= b.
-func le(arg1, arg2 reflect.Value) (bool, error) {
-	// <= is < or ==.
-	lessThan, err := lt(arg1, arg2)
-	if lessThan || err != nil {
-		return lessThan, err
-	}
-	return eq(arg1, arg2)
-}
-
-// gt evaluates the comparison a > b.
-func gt(arg1, arg2 reflect.Value) (bool, error) {
-	// > is the inverse of <=.
-	lessOrEqual, err := le(arg1, arg2)
-	if err != nil {
-		return false, err
-	}
-	return !lessOrEqual, nil
-}
-
-// ge evaluates the comparison a >= b.
-func ge(arg1, arg2 reflect.Value) (bool, error) {
-	// >= is the inverse of <.
-	lessThan, err := lt(arg1, arg2)
-	if err != nil {
-		return false, err
-	}
-	return !lessThan, nil
-}
-
-// HTML escaping.
-
-var (
-	htmlQuot = []byte("&#34;") // shorter than "&quot;"
-	htmlApos = []byte("&#39;") // shorter than "&apos;" and apos was not in HTML until HTML5
-	htmlAmp  = []byte("&amp;")
-	htmlLt   = []byte("&lt;")
-	htmlGt   = []byte("&gt;")
-	htmlNull = []byte("\uFFFD")
-)
-
-// HTMLEscape writes to w the escaped HTML equivalent of the plain text data b.
-func HTMLEscape(w io.Writer, b []byte) {
-	last := 0
-	for i, c := range b {
-		var html []byte
-		switch c {
-		case '\000':
-			html = htmlNull
-		case '"':
-			html = htmlQuot
-		case '\'':
-			html = htmlApos
-		case '&':
-			html = htmlAmp
-		case '<':
-			html = htmlLt
-		case '>':
-			html = htmlGt
-		default:
-			continue
-		}
-		w.Write(b[last:i])
-		w.Write(html)
-		last = i + 1
-	}
-	w.Write(b[last:])
-}
-
-// HTMLEscapeString returns the escaped HTML equivalent of the plain text data s.
-func HTMLEscapeString(s string) string {
-	// Avoid allocation if we can.
-	if !strings.ContainsAny(s, "'\"&<>\000") {
-		return s
-	}
-	var b bytes.Buffer
-	HTMLEscape(&b, []byte(s))
-	return b.String()
-}
-
-// HTMLEscaper returns the escaped HTML equivalent of the textual
-// representation of its arguments.
-func HTMLEscaper(args ...interface{}) string {
-	return HTMLEscapeString(evalArgs(args))
-}
-
-// JavaScript escaping.
-
-var (
-	jsLowUni = []byte(`\u00`)
-	hex      = []byte("0123456789ABCDEF")
-
-	jsBackslash = []byte(`\\`)
-	jsApos      = []byte(`\'`)
-	jsQuot      = []byte(`\"`)
-	jsLt        = []byte(`\u003C`)
-	jsGt        = []byte(`\u003E`)
-	jsAmp       = []byte(`\u0026`)
-	jsEq        = []byte(`\u003D`)
-)
-
-// JSEscape writes to w the escaped JavaScript equivalent of the plain text data b.
-func JSEscape(w io.Writer, b []byte) {
-	last := 0
-	for i := 0; i < len(b); i++ {
-		c := b[i]
-
-		if !jsIsSpecial(rune(c)) {
-			// fast path: nothing to do
-			continue
-		}
-		w.Write(b[last:i])
-
-		if c < utf8.RuneSelf {
-			// Quotes, slashes and angle brackets get quoted.
-			// Control characters get written as \u00XX.
-			switch c {
-			case '\\':
-				w.Write(jsBackslash)
-			case '\'':
-				w.Write(jsApos)
-			case '"':
-				w.Write(jsQuot)
-			case '<':
-				w.Write(jsLt)
-			case '>':
-				w.Write(jsGt)
-			case '&':
-				w.Write(jsAmp)
-			case '=':
-				w.Write(jsEq)
-			default:
-				w.Write(jsLowUni)
-				t, b := c>>4, c&0x0f
-				w.Write(hex[t : t+1])
-				w.Write(hex[b : b+1])
-			}
-		} else {
-			// Unicode rune.
-			r, size := utf8.DecodeRune(b[i:])
-			if unicode.IsPrint(r) {
-				w.Write(b[i : i+size])
-			} else {
-				fmt.Fprintf(w, "\\u%04X", r)
-			}
-			i += size - 1
-		}
-		last = i + 1
-	}
-	w.Write(b[last:])
-}
-
-// JSEscapeString returns the escaped JavaScript equivalent of the plain text data s.
-func JSEscapeString(s string) string {
-	// Avoid allocation if we can.
-	if strings.IndexFunc(s, jsIsSpecial) < 0 {
-		return s
-	}
-	var b bytes.Buffer
-	JSEscape(&b, []byte(s))
-	return b.String()
-}
-
-func jsIsSpecial(r rune) bool {
-	switch r {
-	case '\\', '\'', '"', '<', '>', '&', '=':
-		return true
-	}
-	return r < ' ' || utf8.RuneSelf <= r
-}
-
-// JSEscaper returns the escaped JavaScript equivalent of the textual
-// representation of its arguments.
-func JSEscaper(args ...interface{}) string {
-	return JSEscapeString(evalArgs(args))
-}
-
-// URLQueryEscaper returns the escaped value of the textual representation of
-// its arguments in a form suitable for embedding in a URL query.
-func URLQueryEscaper(args ...interface{}) string {
-	return url.QueryEscape(evalArgs(args))
-}
-
-// evalArgs formats the list of arguments into a string. It is therefore equivalent to
-//	fmt.Sprint(args...)
-// except that each argument is indirected (if a pointer), as required,
-// using the same rules as the default string evaluation during template
-// execution.
-func evalArgs(args []interface{}) string {
-	ok := false
-	var s string
-	// Fast path for simple common case.
-	if len(args) == 1 {
-		s, ok = args[0].(string)
-	}
-	if !ok {
-		for i, arg := range args {
-			a, ok := printableValue(reflect.ValueOf(arg))
-			if ok {
-				args[i] = a
-			} // else let fmt do its thing
-		}
-		s = fmt.Sprint(args...)
-	}
-	return s
-}
diff --git a/go.dev/cmd/internal/text/template/helper.go b/go.dev/cmd/internal/text/template/helper.go
deleted file mode 100644
index e2ce480..0000000
--- a/go.dev/cmd/internal/text/template/helper.go
+++ /dev/null
@@ -1,135 +0,0 @@
-// Copyright 2011 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.
-
-// Helper functions to make constructing templates easier.
-
-package template
-
-import (
-	"fmt"
-	"io/ioutil"
-	"path/filepath"
-)
-
-// Functions and methods to parse templates.
-
-// Must is a helper that wraps a call to a function returning (*Template, error)
-// and panics if the error is non-nil. It is intended for use in variable
-// initializations such as
-//	var t = template.Must(template.New("name").Parse("text"))
-func Must(t *Template, err error) *Template {
-	if err != nil {
-		panic(err)
-	}
-	return t
-}
-
-// ParseFiles creates a new Template and parses the template definitions from
-// the named files. The returned template's name will have the base name and
-// parsed contents of the first file. There must be at least one file.
-// If an error occurs, parsing stops and the returned *Template is nil.
-//
-// When parsing multiple files with the same name in different directories,
-// the last one mentioned will be the one that results.
-// For instance, ParseFiles("a/foo", "b/foo") stores "b/foo" as the template
-// named "foo", while "a/foo" is unavailable.
-func ParseFiles(filenames ...string) (*Template, error) {
-	return parseFiles(nil, readFileOS, filenames...)
-}
-
-// ParseFiles parses the named files and associates the resulting templates with
-// t. If an error occurs, parsing stops and the returned template is nil;
-// otherwise it is t. There must be at least one file.
-// Since the templates created by ParseFiles are named by the base
-// names of the argument files, t should usually have the name of one
-// of the (base) names of the files. If it does not, depending on t's
-// contents before calling ParseFiles, t.Execute may fail. In that
-// case use t.ExecuteTemplate to execute a valid template.
-//
-// When parsing multiple files with the same name in different directories,
-// the last one mentioned will be the one that results.
-func (t *Template) ParseFiles(filenames ...string) (*Template, error) {
-	t.init()
-	return parseFiles(t, readFileOS, filenames...)
-}
-
-// parseFiles is the helper for the method and function. If the argument
-// template is nil, it is created from the first file.
-func parseFiles(t *Template, readFile func(string) (string, []byte, error), filenames ...string) (*Template, error) {
-	if len(filenames) == 0 {
-		// Not really a problem, but be consistent.
-		return nil, fmt.Errorf("template: no files named in call to ParseFiles")
-	}
-	for _, filename := range filenames {
-		name, b, err := readFile(filename)
-		if err != nil {
-			return nil, err
-		}
-		s := string(b)
-		// First template becomes return value if not already defined,
-		// and we use that one for subsequent New calls to associate
-		// all the templates together. Also, if this file has the same name
-		// as t, this file becomes the contents of t, so
-		//  t, err := New(name).Funcs(xxx).ParseFiles(name)
-		// works. Otherwise we create a new template associated with t.
-		var tmpl *Template
-		if t == nil {
-			t = New(name)
-		}
-		if name == t.Name() {
-			tmpl = t
-		} else {
-			tmpl = t.New(name)
-		}
-		_, err = tmpl.Parse(s)
-		if err != nil {
-			return nil, err
-		}
-	}
-	return t, nil
-}
-
-// ParseGlob creates a new Template and parses the template definitions from
-// the files identified by the pattern. The files are matched according to the
-// semantics of filepath.Match, and the pattern must match at least one file.
-// The returned template will have the (base) name and (parsed) contents of the
-// first file matched by the pattern. ParseGlob is equivalent to calling
-// ParseFiles with the list of files matched by the pattern.
-//
-// When parsing multiple files with the same name in different directories,
-// the last one mentioned will be the one that results.
-func ParseGlob(pattern string) (*Template, error) {
-	return parseGlob(nil, pattern)
-}
-
-// ParseGlob parses the template definitions in the files identified by the
-// pattern and associates the resulting templates with t. The files are matched
-// according to the semantics of filepath.Match, and the pattern must match at
-// least one file. ParseGlob is equivalent to calling t.ParseFiles with the
-// list of files matched by the pattern.
-//
-// When parsing multiple files with the same name in different directories,
-// the last one mentioned will be the one that results.
-func (t *Template) ParseGlob(pattern string) (*Template, error) {
-	t.init()
-	return parseGlob(t, pattern)
-}
-
-// parseGlob is the implementation of the function and method ParseGlob.
-func parseGlob(t *Template, pattern string) (*Template, error) {
-	filenames, err := filepath.Glob(pattern)
-	if err != nil {
-		return nil, err
-	}
-	if len(filenames) == 0 {
-		return nil, fmt.Errorf("template: pattern matches no files: %#q", pattern)
-	}
-	return parseFiles(t, readFileOS, filenames...)
-}
-
-func readFileOS(file string) (name string, b []byte, err error) {
-	name = filepath.Base(file)
-	b, err = ioutil.ReadFile(file)
-	return
-}
diff --git a/go.dev/cmd/internal/text/template/multi_test.go b/go.dev/cmd/internal/text/template/multi_test.go
deleted file mode 100644
index 8507c63..0000000
--- a/go.dev/cmd/internal/text/template/multi_test.go
+++ /dev/null
@@ -1,425 +0,0 @@
-// Copyright 2011 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 template
-
-// Tests for multiple-template parsing and execution.
-
-import (
-	"bytes"
-	"fmt"
-	"testing"
-
-	"golang.org/x/website/go.dev/cmd/internal/text/template/parse"
-)
-
-const (
-	noError  = true
-	hasError = false
-)
-
-type multiParseTest struct {
-	name    string
-	input   string
-	ok      bool
-	names   []string
-	results []string
-}
-
-var multiParseTests = []multiParseTest{
-	{"empty", "", noError,
-		nil,
-		nil},
-	{"one", `{{define "foo"}} FOO {{end}}`, noError,
-		[]string{"foo"},
-		[]string{" FOO "}},
-	{"two", `{{define "foo"}} FOO {{end}}{{define "bar"}} BAR {{end}}`, noError,
-		[]string{"foo", "bar"},
-		[]string{" FOO ", " BAR "}},
-	// errors
-	{"missing end", `{{define "foo"}} FOO `, hasError,
-		nil,
-		nil},
-	{"malformed name", `{{define "foo}} FOO `, hasError,
-		nil,
-		nil},
-}
-
-func TestMultiParse(t *testing.T) {
-	for _, test := range multiParseTests {
-		template, err := New("root").Parse(test.input)
-		switch {
-		case err == nil && !test.ok:
-			t.Errorf("%q: expected error; got none", test.name)
-			continue
-		case err != nil && test.ok:
-			t.Errorf("%q: unexpected error: %v", test.name, err)
-			continue
-		case err != nil && !test.ok:
-			// expected error, got one
-			if *debug {
-				fmt.Printf("%s: %s\n\t%s\n", test.name, test.input, err)
-			}
-			continue
-		}
-		if template == nil {
-			continue
-		}
-		if len(template.tmpl) != len(test.names)+1 { // +1 for root
-			t.Errorf("%s: wrong number of templates; wanted %d got %d", test.name, len(test.names), len(template.tmpl))
-			continue
-		}
-		for i, name := range test.names {
-			tmpl, ok := template.tmpl[name]
-			if !ok {
-				t.Errorf("%s: can't find template %q", test.name, name)
-				continue
-			}
-			result := tmpl.Root.String()
-			if result != test.results[i] {
-				t.Errorf("%s=(%q): got\n\t%v\nexpected\n\t%v", test.name, test.input, result, test.results[i])
-			}
-		}
-	}
-}
-
-var multiExecTests = []execTest{
-	{"empty", "", "", nil, true},
-	{"text", "some text", "some text", nil, true},
-	{"invoke x", `{{template "x" .SI}}`, "TEXT", tVal, true},
-	{"invoke x no args", `{{template "x"}}`, "TEXT", tVal, true},
-	{"invoke dot int", `{{template "dot" .I}}`, "17", tVal, true},
-	{"invoke dot []int", `{{template "dot" .SI}}`, "[3 4 5]", tVal, true},
-	{"invoke dotV", `{{template "dotV" .U}}`, "v", tVal, true},
-	{"invoke nested int", `{{template "nested" .I}}`, "17", tVal, true},
-	{"variable declared by template", `{{template "nested" $x:=.SI}},{{index $x 1}}`, "[3 4 5],4", tVal, true},
-
-	// User-defined function: test argument evaluator.
-	{"testFunc literal", `{{oneArg "joe"}}`, "oneArg=joe", tVal, true},
-	{"testFunc .", `{{oneArg .}}`, "oneArg=joe", "joe", true},
-}
-
-// These strings are also in testdata/*.
-const multiText1 = `
-	{{define "x"}}TEXT{{end}}
-	{{define "dotV"}}{{.V}}{{end}}
-`
-
-const multiText2 = `
-	{{define "dot"}}{{.}}{{end}}
-	{{define "nested"}}{{template "dot" .}}{{end}}
-`
-
-func TestMultiExecute(t *testing.T) {
-	// Declare a couple of templates first.
-	template, err := New("root").Parse(multiText1)
-	if err != nil {
-		t.Fatalf("parse error for 1: %s", err)
-	}
-	_, err = template.Parse(multiText2)
-	if err != nil {
-		t.Fatalf("parse error for 2: %s", err)
-	}
-	testExecute(multiExecTests, template, t)
-}
-
-func TestParseFiles(t *testing.T) {
-	_, err := ParseFiles("DOES NOT EXIST")
-	if err == nil {
-		t.Error("expected error for non-existent file; got none")
-	}
-	template := New("root")
-	_, err = template.ParseFiles("testdata/file1.tmpl", "testdata/file2.tmpl")
-	if err != nil {
-		t.Fatalf("error parsing files: %v", err)
-	}
-	testExecute(multiExecTests, template, t)
-}
-
-func TestParseGlob(t *testing.T) {
-	_, err := ParseGlob("DOES NOT EXIST")
-	if err == nil {
-		t.Error("expected error for non-existent file; got none")
-	}
-	_, err = New("error").ParseGlob("[x")
-	if err == nil {
-		t.Error("expected error for bad pattern; got none")
-	}
-	template := New("root")
-	_, err = template.ParseGlob("testdata/file*.tmpl")
-	if err != nil {
-		t.Fatalf("error parsing files: %v", err)
-	}
-	testExecute(multiExecTests, template, t)
-}
-
-// In these tests, actual content (not just template definitions) comes from the parsed files.
-
-var templateFileExecTests = []execTest{
-	{"test", `{{template "tmpl1.tmpl"}}{{template "tmpl2.tmpl"}}`, "template1\n\ny\ntemplate2\n\nx\n", 0, true},
-}
-
-func TestParseFilesWithData(t *testing.T) {
-	template, err := New("root").ParseFiles("testdata/tmpl1.tmpl", "testdata/tmpl2.tmpl")
-	if err != nil {
-		t.Fatalf("error parsing files: %v", err)
-	}
-	testExecute(templateFileExecTests, template, t)
-}
-
-func TestParseGlobWithData(t *testing.T) {
-	template, err := New("root").ParseGlob("testdata/tmpl*.tmpl")
-	if err != nil {
-		t.Fatalf("error parsing files: %v", err)
-	}
-	testExecute(templateFileExecTests, template, t)
-}
-
-const (
-	cloneText1 = `{{define "a"}}{{template "b"}}{{template "c"}}{{end}}`
-	cloneText2 = `{{define "b"}}b{{end}}`
-	cloneText3 = `{{define "c"}}root{{end}}`
-	cloneText4 = `{{define "c"}}clone{{end}}`
-)
-
-func TestClone(t *testing.T) {
-	// Create some templates and clone the root.
-	root, err := New("root").Parse(cloneText1)
-	if err != nil {
-		t.Fatal(err)
-	}
-	_, err = root.Parse(cloneText2)
-	if err != nil {
-		t.Fatal(err)
-	}
-	clone := Must(root.Clone())
-	// Add variants to both.
-	_, err = root.Parse(cloneText3)
-	if err != nil {
-		t.Fatal(err)
-	}
-	_, err = clone.Parse(cloneText4)
-	if err != nil {
-		t.Fatal(err)
-	}
-	// Verify that the clone is self-consistent.
-	for k, v := range clone.tmpl {
-		if k == clone.name && v.tmpl[k] != clone {
-			t.Error("clone does not contain root")
-		}
-		if v != v.tmpl[v.name] {
-			t.Errorf("clone does not contain self for %q", k)
-		}
-	}
-	// Execute root.
-	var b bytes.Buffer
-	err = root.ExecuteTemplate(&b, "a", 0)
-	if err != nil {
-		t.Fatal(err)
-	}
-	if b.String() != "broot" {
-		t.Errorf("expected %q got %q", "broot", b.String())
-	}
-	// Execute copy.
-	b.Reset()
-	err = clone.ExecuteTemplate(&b, "a", 0)
-	if err != nil {
-		t.Fatal(err)
-	}
-	if b.String() != "bclone" {
-		t.Errorf("expected %q got %q", "bclone", b.String())
-	}
-}
-
-func TestAddParseTree(t *testing.T) {
-	// Create some templates.
-	root, err := New("root").Parse(cloneText1)
-	if err != nil {
-		t.Fatal(err)
-	}
-	_, err = root.Parse(cloneText2)
-	if err != nil {
-		t.Fatal(err)
-	}
-	// Add a new parse tree.
-	tree, err := parse.Parse("cloneText3", cloneText3, "", "", nil, builtins())
-	if err != nil {
-		t.Fatal(err)
-	}
-	added, err := root.AddParseTree("c", tree["c"])
-	if err != nil {
-		t.Fatal(err)
-	}
-	// Execute.
-	var b bytes.Buffer
-	err = added.ExecuteTemplate(&b, "a", 0)
-	if err != nil {
-		t.Fatal(err)
-	}
-	if b.String() != "broot" {
-		t.Errorf("expected %q got %q", "broot", b.String())
-	}
-}
-
-// Issue 7032
-func TestAddParseTreeToUnparsedTemplate(t *testing.T) {
-	master := "{{define \"master\"}}{{end}}"
-	tmpl := New("master")
-	tree, err := parse.Parse("master", master, "", "", nil)
-	if err != nil {
-		t.Fatalf("unexpected parse err: %v", err)
-	}
-	masterTree := tree["master"]
-	tmpl.AddParseTree("master", masterTree) // used to panic
-}
-
-func TestRedefinition(t *testing.T) {
-	var tmpl *Template
-	var err error
-	if tmpl, err = New("tmpl1").Parse(`{{define "test"}}foo{{end}}`); err != nil {
-		t.Fatalf("parse 1: %v", err)
-	}
-	if _, err = tmpl.Parse(`{{define "test"}}bar{{end}}`); err != nil {
-		t.Fatalf("got error %v, expected nil", err)
-	}
-	if _, err = tmpl.New("tmpl2").Parse(`{{define "test"}}bar{{end}}`); err != nil {
-		t.Fatalf("got error %v, expected nil", err)
-	}
-}
-
-// Issue 10879
-func TestEmptyTemplateCloneCrash(t *testing.T) {
-	t1 := New("base")
-	t1.Clone() // used to panic
-}
-
-// Issue 10910, 10926
-func TestTemplateLookUp(t *testing.T) {
-	t1 := New("foo")
-	if t1.Lookup("foo") != nil {
-		t.Error("Lookup returned non-nil value for undefined template foo")
-	}
-	t1.New("bar")
-	if t1.Lookup("bar") != nil {
-		t.Error("Lookup returned non-nil value for undefined template bar")
-	}
-	t1.Parse(`{{define "foo"}}test{{end}}`)
-	if t1.Lookup("foo") == nil {
-		t.Error("Lookup returned nil value for defined template")
-	}
-}
-
-func TestNew(t *testing.T) {
-	// template with same name already exists
-	t1, _ := New("test").Parse(`{{define "test"}}foo{{end}}`)
-	t2 := t1.New("test")
-
-	if t1.common != t2.common {
-		t.Errorf("t1 & t2 didn't share common struct; got %v != %v", t1.common, t2.common)
-	}
-	if t1.Tree == nil {
-		t.Error("defined template got nil Tree")
-	}
-	if t2.Tree != nil {
-		t.Error("undefined template got non-nil Tree")
-	}
-
-	containsT1 := false
-	for _, tmpl := range t1.Templates() {
-		if tmpl == t2 {
-			t.Error("Templates included undefined template")
-		}
-		if tmpl == t1 {
-			containsT1 = true
-		}
-	}
-	if !containsT1 {
-		t.Error("Templates didn't include defined template")
-	}
-}
-
-func TestParse(t *testing.T) {
-	// In multiple calls to Parse with the same receiver template, only one call
-	// can contain text other than space, comments, and template definitions
-	t1 := New("test")
-	if _, err := t1.Parse(`{{define "test"}}{{end}}`); err != nil {
-		t.Fatalf("parsing test: %s", err)
-	}
-	if _, err := t1.Parse(`{{define "test"}}{{/* this is a comment */}}{{end}}`); err != nil {
-		t.Fatalf("parsing test: %s", err)
-	}
-	if _, err := t1.Parse(`{{define "test"}}foo{{end}}`); err != nil {
-		t.Fatalf("parsing test: %s", err)
-	}
-}
-
-func TestEmptyTemplate(t *testing.T) {
-	cases := []struct {
-		defn []string
-		in   string
-		want string
-	}{
-		{[]string{"x", "y"}, "", "y"},
-		{[]string{""}, "once", ""},
-		{[]string{"", ""}, "twice", ""},
-		{[]string{"{{.}}", "{{.}}"}, "twice", "twice"},
-		{[]string{"{{/* a comment */}}", "{{/* a comment */}}"}, "comment", ""},
-		{[]string{"{{.}}", ""}, "twice", ""},
-	}
-
-	for i, c := range cases {
-		root := New("root")
-
-		var (
-			m   *Template
-			err error
-		)
-		for _, d := range c.defn {
-			m, err = root.New(c.in).Parse(d)
-			if err != nil {
-				t.Fatal(err)
-			}
-		}
-		buf := &bytes.Buffer{}
-		if err := m.Execute(buf, c.in); err != nil {
-			t.Error(i, err)
-			continue
-		}
-		if buf.String() != c.want {
-			t.Errorf("expected string %q: got %q", c.want, buf.String())
-		}
-	}
-}
-
-// Issue 19249 was a regression in 1.8 caused by the handling of empty
-// templates added in that release, which got different answers depending
-// on the order templates appeared in the internal map.
-func TestIssue19294(t *testing.T) {
-	// The empty block in "xhtml" should be replaced during execution
-	// by the contents of "stylesheet", but if the internal map associating
-	// names with templates is built in the wrong order, the empty block
-	// looks non-empty and this doesn't happen.
-	var inlined = map[string]string{
-		"stylesheet": `{{define "stylesheet"}}stylesheet{{end}}`,
-		"xhtml":      `{{block "stylesheet" .}}{{end}}`,
-	}
-	all := []string{"stylesheet", "xhtml"}
-	for i := 0; i < 100; i++ {
-		res, err := New("title.xhtml").Parse(`{{template "xhtml" .}}`)
-		if err != nil {
-			t.Fatal(err)
-		}
-		for _, name := range all {
-			_, err := res.New(name).Parse(inlined[name])
-			if err != nil {
-				t.Fatal(err)
-			}
-		}
-		var buf bytes.Buffer
-		res.Execute(&buf, 0)
-		if buf.String() != "stylesheet" {
-			t.Fatalf("iteration %d: got %q; expected %q", i, buf.String(), "stylesheet")
-		}
-	}
-}
diff --git a/go.dev/cmd/internal/text/template/option.go b/go.dev/cmd/internal/text/template/option.go
deleted file mode 100644
index addce2d..0000000
--- a/go.dev/cmd/internal/text/template/option.go
+++ /dev/null
@@ -1,74 +0,0 @@
-// 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.
-
-// This file contains the code to handle template options.
-
-package template
-
-import "strings"
-
-// missingKeyAction defines how to respond to indexing a map with a key that is not present.
-type missingKeyAction int
-
-const (
-	mapInvalid   missingKeyAction = iota // Return an invalid reflect.Value.
-	mapZeroValue                         // Return the zero value for the map element.
-	mapError                             // Error out
-)
-
-type option struct {
-	missingKey missingKeyAction
-}
-
-// Option sets options for the template. Options are described by
-// strings, either a simple string or "key=value". There can be at
-// most one equals sign in an option string. If the option string
-// is unrecognized or otherwise invalid, Option panics.
-//
-// Known options:
-//
-// missingkey: Control the behavior during execution if a map is
-// indexed with a key that is not present in the map.
-//	"missingkey=default" or "missingkey=invalid"
-//		The default behavior: Do nothing and continue execution.
-//		If printed, the result of the index operation is the string
-//		"<no value>".
-//	"missingkey=zero"
-//		The operation returns the zero value for the map type's element.
-//	"missingkey=error"
-//		Execution stops immediately with an error.
-//
-func (t *Template) Option(opt ...string) *Template {
-	t.init()
-	for _, s := range opt {
-		t.setOption(s)
-	}
-	return t
-}
-
-func (t *Template) setOption(opt string) {
-	if opt == "" {
-		panic("empty option string")
-	}
-	elems := strings.Split(opt, "=")
-	switch len(elems) {
-	case 2:
-		// key=value
-		switch elems[0] {
-		case "missingkey":
-			switch elems[1] {
-			case "invalid", "default":
-				t.option.missingKey = mapInvalid
-				return
-			case "zero":
-				t.option.missingKey = mapZeroValue
-				return
-			case "error":
-				t.option.missingKey = mapError
-				return
-			}
-		}
-	}
-	panic("unrecognized option: " + opt)
-}
diff --git a/go.dev/cmd/internal/text/template/parse/lex.go b/go.dev/cmd/internal/text/template/parse/lex.go
deleted file mode 100644
index 95e3377..0000000
--- a/go.dev/cmd/internal/text/template/parse/lex.go
+++ /dev/null
@@ -1,682 +0,0 @@
-// Copyright 2011 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 parse
-
-import (
-	"fmt"
-	"strings"
-	"unicode"
-	"unicode/utf8"
-)
-
-// item represents a token or text string returned from the scanner.
-type item struct {
-	typ  itemType // The type of this item.
-	pos  Pos      // The starting position, in bytes, of this item in the input string.
-	val  string   // The value of this item.
-	line int      // The line number at the start of this item.
-}
-
-func (i item) String() string {
-	switch {
-	case i.typ == itemEOF:
-		return "EOF"
-	case i.typ == itemError:
-		return i.val
-	case i.typ > itemKeyword:
-		return fmt.Sprintf("<%s>", i.val)
-	case len(i.val) > 10:
-		return fmt.Sprintf("%.10q...", i.val)
-	}
-	return fmt.Sprintf("%q", i.val)
-}
-
-// itemType identifies the type of lex items.
-type itemType int
-
-const (
-	itemError        itemType = iota // error occurred; value is text of error
-	itemBool                         // boolean constant
-	itemChar                         // printable ASCII character; grab bag for comma etc.
-	itemCharConstant                 // character constant
-	itemComment                      // comment text
-	itemComplex                      // complex constant (1+2i); imaginary is just a number
-	itemAssign                       // equals ('=') introducing an assignment
-	itemDeclare                      // colon-equals (':=') introducing a declaration
-	itemEOF
-	itemField      // alphanumeric identifier starting with '.'
-	itemIdentifier // alphanumeric identifier not starting with '.'
-	itemLeftDelim  // left action delimiter
-	itemLeftParen  // '(' inside action
-	itemNumber     // simple number, including imaginary
-	itemPipe       // pipe symbol
-	itemRawString  // raw quoted string (includes quotes)
-	itemRightDelim // right action delimiter
-	itemRightParen // ')' inside action
-	itemSpace      // run of spaces separating arguments
-	itemString     // quoted string (includes quotes)
-	itemText       // plain text
-	itemVariable   // variable starting with '$', such as '$' or  '$1' or '$hello'
-	// Keywords appear after all the rest.
-	itemKeyword  // used only to delimit the keywords
-	itemBlock    // block keyword
-	itemBreak    // break keyword
-	itemContinue // continue keyword
-	itemDot      // the cursor, spelled '.'
-	itemDefine   // define keyword
-	itemElse     // else keyword
-	itemEnd      // end keyword
-	itemIf       // if keyword
-	itemNil      // the untyped nil constant, easiest to treat as a keyword
-	itemRange    // range keyword
-	itemTemplate // template keyword
-	itemWith     // with keyword
-)
-
-var key = map[string]itemType{
-	".":        itemDot,
-	"block":    itemBlock,
-	"break":    itemBreak,
-	"continue": itemContinue,
-	"define":   itemDefine,
-	"else":     itemElse,
-	"end":      itemEnd,
-	"if":       itemIf,
-	"range":    itemRange,
-	"nil":      itemNil,
-	"template": itemTemplate,
-	"with":     itemWith,
-}
-
-const eof = -1
-
-// Trimming spaces.
-// If the action begins "{{- " rather than "{{", then all space/tab/newlines
-// preceding the action are trimmed; conversely if it ends " -}}" the
-// leading spaces are trimmed. This is done entirely in the lexer; the
-// parser never sees it happen. We require an ASCII space (' ', \t, \r, \n)
-// to be present to avoid ambiguity with things like "{{-3}}". It reads
-// better with the space present anyway. For simplicity, only ASCII
-// does the job.
-const (
-	spaceChars    = " \t\r\n"  // These are the space characters defined by Go itself.
-	trimMarker    = '-'        // Attached to left/right delimiter, trims trailing spaces from preceding/following text.
-	trimMarkerLen = Pos(1 + 1) // marker plus space before or after
-)
-
-// stateFn represents the state of the scanner as a function that returns the next state.
-type stateFn func(*lexer) stateFn
-
-// lexer holds the state of the scanner.
-type lexer struct {
-	name        string    // the name of the input; used only for error reports
-	input       string    // the string being scanned
-	leftDelim   string    // start of action
-	rightDelim  string    // end of action
-	emitComment bool      // emit itemComment tokens.
-	pos         Pos       // current position in the input
-	start       Pos       // start position of this item
-	width       Pos       // width of last rune read from input
-	items       chan item // channel of scanned items
-	parenDepth  int       // nesting depth of ( ) exprs
-	line        int       // 1+number of newlines seen
-	startLine   int       // start line of this item
-	breakOK     bool      // break keyword allowed
-	continueOK  bool      // continue keyword allowed
-}
-
-// next returns the next rune in the input.
-func (l *lexer) next() rune {
-	if int(l.pos) >= len(l.input) {
-		l.width = 0
-		return eof
-	}
-	r, w := utf8.DecodeRuneInString(l.input[l.pos:])
-	l.width = Pos(w)
-	l.pos += l.width
-	if r == '\n' {
-		l.line++
-	}
-	return r
-}
-
-// peek returns but does not consume the next rune in the input.
-func (l *lexer) peek() rune {
-	r := l.next()
-	l.backup()
-	return r
-}
-
-// backup steps back one rune. Can only be called once per call of next.
-func (l *lexer) backup() {
-	l.pos -= l.width
-	// Correct newline count.
-	if l.width == 1 && l.input[l.pos] == '\n' {
-		l.line--
-	}
-}
-
-// emit passes an item back to the client.
-func (l *lexer) emit(t itemType) {
-	l.items <- item{t, l.start, l.input[l.start:l.pos], l.startLine}
-	l.start = l.pos
-	l.startLine = l.line
-}
-
-// ignore skips over the pending input before this point.
-func (l *lexer) ignore() {
-	l.line += strings.Count(l.input[l.start:l.pos], "\n")
-	l.start = l.pos
-	l.startLine = l.line
-}
-
-// accept consumes the next rune if it's from the valid set.
-func (l *lexer) accept(valid string) bool {
-	if strings.ContainsRune(valid, l.next()) {
-		return true
-	}
-	l.backup()
-	return false
-}
-
-// acceptRun consumes a run of runes from the valid set.
-func (l *lexer) acceptRun(valid string) {
-	for strings.ContainsRune(valid, l.next()) {
-	}
-	l.backup()
-}
-
-// errorf returns an error token and terminates the scan by passing
-// back a nil pointer that will be the next state, terminating l.nextItem.
-func (l *lexer) errorf(format string, args ...interface{}) stateFn {
-	l.items <- item{itemError, l.start, fmt.Sprintf(format, args...), l.startLine}
-	return nil
-}
-
-// nextItem returns the next item from the input.
-// Called by the parser, not in the lexing goroutine.
-func (l *lexer) nextItem() item {
-	return <-l.items
-}
-
-// drain drains the output so the lexing goroutine will exit.
-// Called by the parser, not in the lexing goroutine.
-func (l *lexer) drain() {
-	for range l.items {
-	}
-}
-
-// lex creates a new scanner for the input string.
-func lex(name, input, left, right string, emitComment bool) *lexer {
-	if left == "" {
-		left = leftDelim
-	}
-	if right == "" {
-		right = rightDelim
-	}
-	l := &lexer{
-		name:        name,
-		input:       input,
-		leftDelim:   left,
-		rightDelim:  right,
-		emitComment: emitComment,
-		items:       make(chan item),
-		line:        1,
-		startLine:   1,
-	}
-	go l.run()
-	return l
-}
-
-// run runs the state machine for the lexer.
-func (l *lexer) run() {
-	for state := lexText; state != nil; {
-		state = state(l)
-	}
-	close(l.items)
-}
-
-// state functions
-
-const (
-	leftDelim    = "{{"
-	rightDelim   = "}}"
-	leftComment  = "/*"
-	rightComment = "*/"
-)
-
-// lexText scans until an opening action delimiter, "{{".
-func lexText(l *lexer) stateFn {
-	l.width = 0
-	if x := strings.Index(l.input[l.pos:], l.leftDelim); x >= 0 {
-		ldn := Pos(len(l.leftDelim))
-		l.pos += Pos(x)
-		trimLength := Pos(0)
-		if hasLeftTrimMarker(l.input[l.pos+ldn:]) {
-			trimLength = rightTrimLength(l.input[l.start:l.pos])
-		}
-		l.pos -= trimLength
-		if l.pos > l.start {
-			l.line += strings.Count(l.input[l.start:l.pos], "\n")
-			l.emit(itemText)
-		}
-		l.pos += trimLength
-		l.ignore()
-		return lexLeftDelim
-	}
-	l.pos = Pos(len(l.input))
-	// Correctly reached EOF.
-	if l.pos > l.start {
-		l.line += strings.Count(l.input[l.start:l.pos], "\n")
-		l.emit(itemText)
-	}
-	l.emit(itemEOF)
-	return nil
-}
-
-// rightTrimLength returns the length of the spaces at the end of the string.
-func rightTrimLength(s string) Pos {
-	return Pos(len(s) - len(strings.TrimRight(s, spaceChars)))
-}
-
-// atRightDelim reports whether the lexer is at a right delimiter, possibly preceded by a trim marker.
-func (l *lexer) atRightDelim() (delim, trimSpaces bool) {
-	if hasRightTrimMarker(l.input[l.pos:]) && strings.HasPrefix(l.input[l.pos+trimMarkerLen:], l.rightDelim) { // With trim marker.
-		return true, true
-	}
-	if strings.HasPrefix(l.input[l.pos:], l.rightDelim) { // Without trim marker.
-		return true, false
-	}
-	return false, false
-}
-
-// leftTrimLength returns the length of the spaces at the beginning of the string.
-func leftTrimLength(s string) Pos {
-	return Pos(len(s) - len(strings.TrimLeft(s, spaceChars)))
-}
-
-// lexLeftDelim scans the left delimiter, which is known to be present, possibly with a trim marker.
-func lexLeftDelim(l *lexer) stateFn {
-	l.pos += Pos(len(l.leftDelim))
-	trimSpace := hasLeftTrimMarker(l.input[l.pos:])
-	afterMarker := Pos(0)
-	if trimSpace {
-		afterMarker = trimMarkerLen
-	}
-	if strings.HasPrefix(l.input[l.pos+afterMarker:], leftComment) {
-		l.pos += afterMarker
-		l.ignore()
-		return lexComment
-	}
-	l.emit(itemLeftDelim)
-	l.pos += afterMarker
-	l.ignore()
-	l.parenDepth = 0
-	return lexInsideAction
-}
-
-// lexComment scans a comment. The left comment marker is known to be present.
-func lexComment(l *lexer) stateFn {
-	l.pos += Pos(len(leftComment))
-	i := strings.Index(l.input[l.pos:], rightComment)
-	if i < 0 {
-		return l.errorf("unclosed comment")
-	}
-	l.pos += Pos(i + len(rightComment))
-	delim, trimSpace := l.atRightDelim()
-	if !delim {
-		return l.errorf("comment ends before closing delimiter")
-	}
-	if l.emitComment {
-		l.emit(itemComment)
-	}
-	if trimSpace {
-		l.pos += trimMarkerLen
-	}
-	l.pos += Pos(len(l.rightDelim))
-	if trimSpace {
-		l.pos += leftTrimLength(l.input[l.pos:])
-	}
-	l.ignore()
-	return lexText
-}
-
-// lexRightDelim scans the right delimiter, which is known to be present, possibly with a trim marker.
-func lexRightDelim(l *lexer) stateFn {
-	trimSpace := hasRightTrimMarker(l.input[l.pos:])
-	if trimSpace {
-		l.pos += trimMarkerLen
-		l.ignore()
-	}
-	l.pos += Pos(len(l.rightDelim))
-	l.emit(itemRightDelim)
-	if trimSpace {
-		l.pos += leftTrimLength(l.input[l.pos:])
-		l.ignore()
-	}
-	return lexText
-}
-
-// lexInsideAction scans the elements inside action delimiters.
-func lexInsideAction(l *lexer) stateFn {
-	// Either number, quoted string, or identifier.
-	// Spaces separate arguments; runs of spaces turn into itemSpace.
-	// Pipe symbols separate and are emitted.
-	delim, _ := l.atRightDelim()
-	if delim {
-		if l.parenDepth == 0 {
-			return lexRightDelim
-		}
-		return l.errorf("unclosed left paren")
-	}
-	switch r := l.next(); {
-	case r == eof:
-		return l.errorf("unclosed action")
-	case isSpace(r):
-		l.backup() // Put space back in case we have " -}}".
-		return lexSpace
-	case r == '=':
-		l.emit(itemAssign)
-	case r == ':':
-		if l.next() != '=' {
-			return l.errorf("expected :=")
-		}
-		l.emit(itemDeclare)
-	case r == '|':
-		l.emit(itemPipe)
-	case r == '"':
-		return lexQuote
-	case r == '`':
-		return lexRawQuote
-	case r == '$':
-		return lexVariable
-	case r == '\'':
-		return lexChar
-	case r == '.':
-		// special look-ahead for ".field" so we don't break l.backup().
-		if l.pos < Pos(len(l.input)) {
-			r := l.input[l.pos]
-			if r < '0' || '9' < r {
-				return lexField
-			}
-		}
-		fallthrough // '.' can start a number.
-	case r == '+' || r == '-' || ('0' <= r && r <= '9'):
-		l.backup()
-		return lexNumber
-	case isAlphaNumeric(r):
-		l.backup()
-		return lexIdentifier
-	case r == '(':
-		l.emit(itemLeftParen)
-		l.parenDepth++
-	case r == ')':
-		l.emit(itemRightParen)
-		l.parenDepth--
-		if l.parenDepth < 0 {
-			return l.errorf("unexpected right paren %#U", r)
-		}
-	case r <= unicode.MaxASCII && unicode.IsPrint(r):
-		l.emit(itemChar)
-	default:
-		return l.errorf("unrecognized character in action: %#U", r)
-	}
-	return lexInsideAction
-}
-
-// lexSpace scans a run of space characters.
-// We have not consumed the first space, which is known to be present.
-// Take care if there is a trim-marked right delimiter, which starts with a space.
-func lexSpace(l *lexer) stateFn {
-	var r rune
-	var numSpaces int
-	for {
-		r = l.peek()
-		if !isSpace(r) {
-			break
-		}
-		l.next()
-		numSpaces++
-	}
-	// Be careful about a trim-marked closing delimiter, which has a minus
-	// after a space. We know there is a space, so check for the '-' that might follow.
-	if hasRightTrimMarker(l.input[l.pos-1:]) && strings.HasPrefix(l.input[l.pos-1+trimMarkerLen:], l.rightDelim) {
-		l.backup() // Before the space.
-		if numSpaces == 1 {
-			return lexRightDelim // On the delim, so go right to that.
-		}
-	}
-	l.emit(itemSpace)
-	return lexInsideAction
-}
-
-// lexIdentifier scans an alphanumeric.
-func lexIdentifier(l *lexer) stateFn {
-Loop:
-	for {
-		switch r := l.next(); {
-		case isAlphaNumeric(r):
-			// absorb.
-		default:
-			l.backup()
-			word := l.input[l.start:l.pos]
-			if !l.atTerminator() {
-				return l.errorf("bad character %#U", r)
-			}
-			switch {
-			case key[word] > itemKeyword:
-				item := key[word]
-				if item == itemBreak && !l.breakOK || item == itemContinue && !l.continueOK {
-					l.emit(itemIdentifier)
-				} else {
-					l.emit(item)
-				}
-			case word[0] == '.':
-				l.emit(itemField)
-			case word == "true", word == "false":
-				l.emit(itemBool)
-			default:
-				l.emit(itemIdentifier)
-			}
-			break Loop
-		}
-	}
-	return lexInsideAction
-}
-
-// lexField scans a field: .Alphanumeric.
-// The . has been scanned.
-func lexField(l *lexer) stateFn {
-	return lexFieldOrVariable(l, itemField)
-}
-
-// lexVariable scans a Variable: $Alphanumeric.
-// The $ has been scanned.
-func lexVariable(l *lexer) stateFn {
-	if l.atTerminator() { // Nothing interesting follows -> "$".
-		l.emit(itemVariable)
-		return lexInsideAction
-	}
-	return lexFieldOrVariable(l, itemVariable)
-}
-
-// lexVariable scans a field or variable: [.$]Alphanumeric.
-// The . or $ has been scanned.
-func lexFieldOrVariable(l *lexer, typ itemType) stateFn {
-	if l.atTerminator() { // Nothing interesting follows -> "." or "$".
-		if typ == itemVariable {
-			l.emit(itemVariable)
-		} else {
-			l.emit(itemDot)
-		}
-		return lexInsideAction
-	}
-	var r rune
-	for {
-		r = l.next()
-		if !isAlphaNumeric(r) {
-			l.backup()
-			break
-		}
-	}
-	if !l.atTerminator() {
-		return l.errorf("bad character %#U", r)
-	}
-	l.emit(typ)
-	return lexInsideAction
-}
-
-// atTerminator reports whether the input is at valid termination character to
-// appear after an identifier. Breaks .X.Y into two pieces. Also catches cases
-// like "$x+2" not being acceptable without a space, in case we decide one
-// day to implement arithmetic.
-func (l *lexer) atTerminator() bool {
-	r := l.peek()
-	if isSpace(r) {
-		return true
-	}
-	switch r {
-	case eof, '.', ',', '|', ':', ')', '(':
-		return true
-	}
-	// Does r start the delimiter? This can be ambiguous (with delim=="//", $x/2 will
-	// succeed but should fail) but only in extremely rare cases caused by willfully
-	// bad choice of delimiter.
-	if rd, _ := utf8.DecodeRuneInString(l.rightDelim); rd == r {
-		return true
-	}
-	return false
-}
-
-// lexChar scans a character constant. The initial quote is already
-// scanned. Syntax checking is done by the parser.
-func lexChar(l *lexer) stateFn {
-Loop:
-	for {
-		switch l.next() {
-		case '\\':
-			if r := l.next(); r != eof && r != '\n' {
-				break
-			}
-			fallthrough
-		case eof, '\n':
-			return l.errorf("unterminated character constant")
-		case '\'':
-			break Loop
-		}
-	}
-	l.emit(itemCharConstant)
-	return lexInsideAction
-}
-
-// lexNumber scans a number: decimal, octal, hex, float, or imaginary. This
-// isn't a perfect number scanner - for instance it accepts "." and "0x0.2"
-// and "089" - but when it's wrong the input is invalid and the parser (via
-// strconv) will notice.
-func lexNumber(l *lexer) stateFn {
-	if !l.scanNumber() {
-		return l.errorf("bad number syntax: %q", l.input[l.start:l.pos])
-	}
-	if sign := l.peek(); sign == '+' || sign == '-' {
-		// Complex: 1+2i. No spaces, must end in 'i'.
-		if !l.scanNumber() || l.input[l.pos-1] != 'i' {
-			return l.errorf("bad number syntax: %q", l.input[l.start:l.pos])
-		}
-		l.emit(itemComplex)
-	} else {
-		l.emit(itemNumber)
-	}
-	return lexInsideAction
-}
-
-func (l *lexer) scanNumber() bool {
-	// Optional leading sign.
-	l.accept("+-")
-	// Is it hex?
-	digits := "0123456789_"
-	if l.accept("0") {
-		// Note: Leading 0 does not mean octal in floats.
-		if l.accept("xX") {
-			digits = "0123456789abcdefABCDEF_"
-		} else if l.accept("oO") {
-			digits = "01234567_"
-		} else if l.accept("bB") {
-			digits = "01_"
-		}
-	}
-	l.acceptRun(digits)
-	if l.accept(".") {
-		l.acceptRun(digits)
-	}
-	if len(digits) == 10+1 && l.accept("eE") {
-		l.accept("+-")
-		l.acceptRun("0123456789_")
-	}
-	if len(digits) == 16+6+1 && l.accept("pP") {
-		l.accept("+-")
-		l.acceptRun("0123456789_")
-	}
-	// Is it imaginary?
-	l.accept("i")
-	// Next thing mustn't be alphanumeric.
-	if isAlphaNumeric(l.peek()) {
-		l.next()
-		return false
-	}
-	return true
-}
-
-// lexQuote scans a quoted string.
-func lexQuote(l *lexer) stateFn {
-Loop:
-	for {
-		switch l.next() {
-		case '\\':
-			if r := l.next(); r != eof && r != '\n' {
-				break
-			}
-			fallthrough
-		case eof, '\n':
-			return l.errorf("unterminated quoted string")
-		case '"':
-			break Loop
-		}
-	}
-	l.emit(itemString)
-	return lexInsideAction
-}
-
-// lexRawQuote scans a raw quoted string.
-func lexRawQuote(l *lexer) stateFn {
-Loop:
-	for {
-		switch l.next() {
-		case eof:
-			return l.errorf("unterminated raw quoted string")
-		case '`':
-			break Loop
-		}
-	}
-	l.emit(itemRawString)
-	return lexInsideAction
-}
-
-// isSpace reports whether r is a space character.
-func isSpace(r rune) bool {
-	return r == ' ' || r == '\t' || r == '\r' || r == '\n'
-}
-
-// isAlphaNumeric reports whether r is an alphabetic, digit, or underscore.
-func isAlphaNumeric(r rune) bool {
-	return r == '_' || unicode.IsLetter(r) || unicode.IsDigit(r)
-}
-
-func hasLeftTrimMarker(s string) bool {
-	return len(s) >= 2 && s[0] == trimMarker && isSpace(rune(s[1]))
-}
-
-func hasRightTrimMarker(s string) bool {
-	return len(s) >= 2 && isSpace(rune(s[0])) && s[1] == trimMarker
-}
diff --git a/go.dev/cmd/internal/text/template/parse/lex_test.go b/go.dev/cmd/internal/text/template/parse/lex_test.go
deleted file mode 100644
index df6aabf..0000000
--- a/go.dev/cmd/internal/text/template/parse/lex_test.go
+++ /dev/null
@@ -1,559 +0,0 @@
-// Copyright 2011 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 parse
-
-import (
-	"fmt"
-	"testing"
-)
-
-// Make the types prettyprint.
-var itemName = map[itemType]string{
-	itemError:        "error",
-	itemBool:         "bool",
-	itemChar:         "char",
-	itemCharConstant: "charconst",
-	itemComment:      "comment",
-	itemComplex:      "complex",
-	itemDeclare:      ":=",
-	itemEOF:          "EOF",
-	itemField:        "field",
-	itemIdentifier:   "identifier",
-	itemLeftDelim:    "left delim",
-	itemLeftParen:    "(",
-	itemNumber:       "number",
-	itemPipe:         "pipe",
-	itemRawString:    "raw string",
-	itemRightDelim:   "right delim",
-	itemRightParen:   ")",
-	itemSpace:        "space",
-	itemString:       "string",
-	itemVariable:     "variable",
-
-	// keywords
-	itemDot:      ".",
-	itemBlock:    "block",
-	itemBreak:    "break",
-	itemContinue: "continue",
-	itemDefine:   "define",
-	itemElse:     "else",
-	itemIf:       "if",
-	itemEnd:      "end",
-	itemNil:      "nil",
-	itemRange:    "range",
-	itemTemplate: "template",
-	itemWith:     "with",
-}
-
-func (i itemType) String() string {
-	s := itemName[i]
-	if s == "" {
-		return fmt.Sprintf("item%d", int(i))
-	}
-	return s
-}
-
-type lexTest struct {
-	name  string
-	input string
-	items []item
-}
-
-func mkItem(typ itemType, text string) item {
-	return item{
-		typ: typ,
-		val: text,
-	}
-}
-
-var (
-	tDot        = mkItem(itemDot, ".")
-	tBlock      = mkItem(itemBlock, "block")
-	tEOF        = mkItem(itemEOF, "")
-	tFor        = mkItem(itemIdentifier, "for")
-	tLeft       = mkItem(itemLeftDelim, "{{")
-	tLpar       = mkItem(itemLeftParen, "(")
-	tPipe       = mkItem(itemPipe, "|")
-	tQuote      = mkItem(itemString, `"abc \n\t\" "`)
-	tRange      = mkItem(itemRange, "range")
-	tRight      = mkItem(itemRightDelim, "}}")
-	tRpar       = mkItem(itemRightParen, ")")
-	tSpace      = mkItem(itemSpace, " ")
-	raw         = "`" + `abc\n\t\" ` + "`"
-	rawNL       = "`now is{{\n}}the time`" // Contains newline inside raw quote.
-	tRawQuote   = mkItem(itemRawString, raw)
-	tRawQuoteNL = mkItem(itemRawString, rawNL)
-)
-
-var lexTests = []lexTest{
-	{"empty", "", []item{tEOF}},
-	{"spaces", " \t\n", []item{mkItem(itemText, " \t\n"), tEOF}},
-	{"text", `now is the time`, []item{mkItem(itemText, "now is the time"), tEOF}},
-	{"text with comment", "hello-{{/* this is a comment */}}-world", []item{
-		mkItem(itemText, "hello-"),
-		mkItem(itemComment, "/* this is a comment */"),
-		mkItem(itemText, "-world"),
-		tEOF,
-	}},
-	{"punctuation", "{{,@% }}", []item{
-		tLeft,
-		mkItem(itemChar, ","),
-		mkItem(itemChar, "@"),
-		mkItem(itemChar, "%"),
-		tSpace,
-		tRight,
-		tEOF,
-	}},
-	{"parens", "{{((3))}}", []item{
-		tLeft,
-		tLpar,
-		tLpar,
-		mkItem(itemNumber, "3"),
-		tRpar,
-		tRpar,
-		tRight,
-		tEOF,
-	}},
-	{"empty action", `{{}}`, []item{tLeft, tRight, tEOF}},
-	{"for", `{{for}}`, []item{tLeft, tFor, tRight, tEOF}},
-	{"block", `{{block "foo" .}}`, []item{
-		tLeft, tBlock, tSpace, mkItem(itemString, `"foo"`), tSpace, tDot, tRight, tEOF,
-	}},
-	{"quote", `{{"abc \n\t\" "}}`, []item{tLeft, tQuote, tRight, tEOF}},
-	{"raw quote", "{{" + raw + "}}", []item{tLeft, tRawQuote, tRight, tEOF}},
-	{"raw quote with newline", "{{" + rawNL + "}}", []item{tLeft, tRawQuoteNL, tRight, tEOF}},
-	{"numbers", "{{1 02 0x14 0X14 -7.2i 1e3 1E3 +1.2e-4 4.2i 1+2i 1_2 0x1.e_fp4 0X1.E_FP4}}", []item{
-		tLeft,
-		mkItem(itemNumber, "1"),
-		tSpace,
-		mkItem(itemNumber, "02"),
-		tSpace,
-		mkItem(itemNumber, "0x14"),
-		tSpace,
-		mkItem(itemNumber, "0X14"),
-		tSpace,
-		mkItem(itemNumber, "-7.2i"),
-		tSpace,
-		mkItem(itemNumber, "1e3"),
-		tSpace,
-		mkItem(itemNumber, "1E3"),
-		tSpace,
-		mkItem(itemNumber, "+1.2e-4"),
-		tSpace,
-		mkItem(itemNumber, "4.2i"),
-		tSpace,
-		mkItem(itemComplex, "1+2i"),
-		tSpace,
-		mkItem(itemNumber, "1_2"),
-		tSpace,
-		mkItem(itemNumber, "0x1.e_fp4"),
-		tSpace,
-		mkItem(itemNumber, "0X1.E_FP4"),
-		tRight,
-		tEOF,
-	}},
-	{"characters", `{{'a' '\n' '\'' '\\' '\u00FF' '\xFF' '本'}}`, []item{
-		tLeft,
-		mkItem(itemCharConstant, `'a'`),
-		tSpace,
-		mkItem(itemCharConstant, `'\n'`),
-		tSpace,
-		mkItem(itemCharConstant, `'\''`),
-		tSpace,
-		mkItem(itemCharConstant, `'\\'`),
-		tSpace,
-		mkItem(itemCharConstant, `'\u00FF'`),
-		tSpace,
-		mkItem(itemCharConstant, `'\xFF'`),
-		tSpace,
-		mkItem(itemCharConstant, `'本'`),
-		tRight,
-		tEOF,
-	}},
-	{"bools", "{{true false}}", []item{
-		tLeft,
-		mkItem(itemBool, "true"),
-		tSpace,
-		mkItem(itemBool, "false"),
-		tRight,
-		tEOF,
-	}},
-	{"dot", "{{.}}", []item{
-		tLeft,
-		tDot,
-		tRight,
-		tEOF,
-	}},
-	{"nil", "{{nil}}", []item{
-		tLeft,
-		mkItem(itemNil, "nil"),
-		tRight,
-		tEOF,
-	}},
-	{"dots", "{{.x . .2 .x.y.z}}", []item{
-		tLeft,
-		mkItem(itemField, ".x"),
-		tSpace,
-		tDot,
-		tSpace,
-		mkItem(itemNumber, ".2"),
-		tSpace,
-		mkItem(itemField, ".x"),
-		mkItem(itemField, ".y"),
-		mkItem(itemField, ".z"),
-		tRight,
-		tEOF,
-	}},
-	{"keywords", "{{range if else end with}}", []item{
-		tLeft,
-		mkItem(itemRange, "range"),
-		tSpace,
-		mkItem(itemIf, "if"),
-		tSpace,
-		mkItem(itemElse, "else"),
-		tSpace,
-		mkItem(itemEnd, "end"),
-		tSpace,
-		mkItem(itemWith, "with"),
-		tRight,
-		tEOF,
-	}},
-	{"variables", "{{$c := printf $ $hello $23 $ $var.Field .Method}}", []item{
-		tLeft,
-		mkItem(itemVariable, "$c"),
-		tSpace,
-		mkItem(itemDeclare, ":="),
-		tSpace,
-		mkItem(itemIdentifier, "printf"),
-		tSpace,
-		mkItem(itemVariable, "$"),
-		tSpace,
-		mkItem(itemVariable, "$hello"),
-		tSpace,
-		mkItem(itemVariable, "$23"),
-		tSpace,
-		mkItem(itemVariable, "$"),
-		tSpace,
-		mkItem(itemVariable, "$var"),
-		mkItem(itemField, ".Field"),
-		tSpace,
-		mkItem(itemField, ".Method"),
-		tRight,
-		tEOF,
-	}},
-	{"variable invocation", "{{$x 23}}", []item{
-		tLeft,
-		mkItem(itemVariable, "$x"),
-		tSpace,
-		mkItem(itemNumber, "23"),
-		tRight,
-		tEOF,
-	}},
-	{"pipeline", `intro {{echo hi 1.2 |noargs|args 1 "hi"}} outro`, []item{
-		mkItem(itemText, "intro "),
-		tLeft,
-		mkItem(itemIdentifier, "echo"),
-		tSpace,
-		mkItem(itemIdentifier, "hi"),
-		tSpace,
-		mkItem(itemNumber, "1.2"),
-		tSpace,
-		tPipe,
-		mkItem(itemIdentifier, "noargs"),
-		tPipe,
-		mkItem(itemIdentifier, "args"),
-		tSpace,
-		mkItem(itemNumber, "1"),
-		tSpace,
-		mkItem(itemString, `"hi"`),
-		tRight,
-		mkItem(itemText, " outro"),
-		tEOF,
-	}},
-	{"declaration", "{{$v := 3}}", []item{
-		tLeft,
-		mkItem(itemVariable, "$v"),
-		tSpace,
-		mkItem(itemDeclare, ":="),
-		tSpace,
-		mkItem(itemNumber, "3"),
-		tRight,
-		tEOF,
-	}},
-	{"2 declarations", "{{$v , $w := 3}}", []item{
-		tLeft,
-		mkItem(itemVariable, "$v"),
-		tSpace,
-		mkItem(itemChar, ","),
-		tSpace,
-		mkItem(itemVariable, "$w"),
-		tSpace,
-		mkItem(itemDeclare, ":="),
-		tSpace,
-		mkItem(itemNumber, "3"),
-		tRight,
-		tEOF,
-	}},
-	{"field of parenthesized expression", "{{(.X).Y}}", []item{
-		tLeft,
-		tLpar,
-		mkItem(itemField, ".X"),
-		tRpar,
-		mkItem(itemField, ".Y"),
-		tRight,
-		tEOF,
-	}},
-	{"trimming spaces before and after", "hello- {{- 3 -}} -world", []item{
-		mkItem(itemText, "hello-"),
-		tLeft,
-		mkItem(itemNumber, "3"),
-		tRight,
-		mkItem(itemText, "-world"),
-		tEOF,
-	}},
-	{"trimming spaces before and after comment", "hello- {{- /* hello */ -}} -world", []item{
-		mkItem(itemText, "hello-"),
-		mkItem(itemComment, "/* hello */"),
-		mkItem(itemText, "-world"),
-		tEOF,
-	}},
-	// errors
-	{"badchar", "#{{\x01}}", []item{
-		mkItem(itemText, "#"),
-		tLeft,
-		mkItem(itemError, "unrecognized character in action: U+0001"),
-	}},
-	{"unclosed action", "{{", []item{
-		tLeft,
-		mkItem(itemError, "unclosed action"),
-	}},
-	{"EOF in action", "{{range", []item{
-		tLeft,
-		tRange,
-		mkItem(itemError, "unclosed action"),
-	}},
-	{"unclosed quote", "{{\"\n\"}}", []item{
-		tLeft,
-		mkItem(itemError, "unterminated quoted string"),
-	}},
-	{"unclosed raw quote", "{{`xx}}", []item{
-		tLeft,
-		mkItem(itemError, "unterminated raw quoted string"),
-	}},
-	{"unclosed char constant", "{{'\n}}", []item{
-		tLeft,
-		mkItem(itemError, "unterminated character constant"),
-	}},
-	{"bad number", "{{3k}}", []item{
-		tLeft,
-		mkItem(itemError, `bad number syntax: "3k"`),
-	}},
-	{"unclosed paren", "{{(3}}", []item{
-		tLeft,
-		tLpar,
-		mkItem(itemNumber, "3"),
-		mkItem(itemError, `unclosed left paren`),
-	}},
-	{"extra right paren", "{{3)}}", []item{
-		tLeft,
-		mkItem(itemNumber, "3"),
-		tRpar,
-		mkItem(itemError, `unexpected right paren U+0029 ')'`),
-	}},
-
-	// Fixed bugs
-	// Many elements in an action blew the lookahead until
-	// we made lexInsideAction not loop.
-	{"long pipeline deadlock", "{{|||||}}", []item{
-		tLeft,
-		tPipe,
-		tPipe,
-		tPipe,
-		tPipe,
-		tPipe,
-		tRight,
-		tEOF,
-	}},
-	{"text with bad comment", "hello-{{/*/}}-world", []item{
-		mkItem(itemText, "hello-"),
-		mkItem(itemError, `unclosed comment`),
-	}},
-	{"text with comment close separated from delim", "hello-{{/* */ }}-world", []item{
-		mkItem(itemText, "hello-"),
-		mkItem(itemError, `comment ends before closing delimiter`),
-	}},
-	// This one is an error that we can't catch because it breaks templates with
-	// minimized JavaScript. Should have fixed it before Go 1.1.
-	{"unmatched right delimiter", "hello-{.}}-world", []item{
-		mkItem(itemText, "hello-{.}}-world"),
-		tEOF,
-	}},
-}
-
-// collect gathers the emitted items into a slice.
-func collect(t *lexTest, left, right string) (items []item) {
-	l := lex(t.name, t.input, left, right, true)
-	for {
-		item := l.nextItem()
-		items = append(items, item)
-		if item.typ == itemEOF || item.typ == itemError {
-			break
-		}
-	}
-	return
-}
-
-func equal(i1, i2 []item, checkPos bool) bool {
-	if len(i1) != len(i2) {
-		return false
-	}
-	for k := range i1 {
-		if i1[k].typ != i2[k].typ {
-			return false
-		}
-		if i1[k].val != i2[k].val {
-			return false
-		}
-		if checkPos && i1[k].pos != i2[k].pos {
-			return false
-		}
-		if checkPos && i1[k].line != i2[k].line {
-			return false
-		}
-	}
-	return true
-}
-
-func TestLex(t *testing.T) {
-	for _, test := range lexTests {
-		items := collect(&test, "", "")
-		if !equal(items, test.items, false) {
-			t.Errorf("%s: got\n\t%+v\nexpected\n\t%v", test.name, items, test.items)
-		}
-	}
-}
-
-// Some easy cases from above, but with delimiters $$ and @@
-var lexDelimTests = []lexTest{
-	{"punctuation", "$$,@%{{}}@@", []item{
-		tLeftDelim,
-		mkItem(itemChar, ","),
-		mkItem(itemChar, "@"),
-		mkItem(itemChar, "%"),
-		mkItem(itemChar, "{"),
-		mkItem(itemChar, "{"),
-		mkItem(itemChar, "}"),
-		mkItem(itemChar, "}"),
-		tRightDelim,
-		tEOF,
-	}},
-	{"empty action", `$$@@`, []item{tLeftDelim, tRightDelim, tEOF}},
-	{"for", `$$for@@`, []item{tLeftDelim, tFor, tRightDelim, tEOF}},
-	{"quote", `$$"abc \n\t\" "@@`, []item{tLeftDelim, tQuote, tRightDelim, tEOF}},
-	{"raw quote", "$$" + raw + "@@", []item{tLeftDelim, tRawQuote, tRightDelim, tEOF}},
-}
-
-var (
-	tLeftDelim  = mkItem(itemLeftDelim, "$$")
-	tRightDelim = mkItem(itemRightDelim, "@@")
-)
-
-func TestDelims(t *testing.T) {
-	for _, test := range lexDelimTests {
-		items := collect(&test, "$$", "@@")
-		if !equal(items, test.items, false) {
-			t.Errorf("%s: got\n\t%v\nexpected\n\t%v", test.name, items, test.items)
-		}
-	}
-}
-
-var lexPosTests = []lexTest{
-	{"empty", "", []item{{itemEOF, 0, "", 1}}},
-	{"punctuation", "{{,@%#}}", []item{
-		{itemLeftDelim, 0, "{{", 1},
-		{itemChar, 2, ",", 1},
-		{itemChar, 3, "@", 1},
-		{itemChar, 4, "%", 1},
-		{itemChar, 5, "#", 1},
-		{itemRightDelim, 6, "}}", 1},
-		{itemEOF, 8, "", 1},
-	}},
-	{"sample", "0123{{hello}}xyz", []item{
-		{itemText, 0, "0123", 1},
-		{itemLeftDelim, 4, "{{", 1},
-		{itemIdentifier, 6, "hello", 1},
-		{itemRightDelim, 11, "}}", 1},
-		{itemText, 13, "xyz", 1},
-		{itemEOF, 16, "", 1},
-	}},
-	{"trimafter", "{{x -}}\n{{y}}", []item{
-		{itemLeftDelim, 0, "{{", 1},
-		{itemIdentifier, 2, "x", 1},
-		{itemRightDelim, 5, "}}", 1},
-		{itemLeftDelim, 8, "{{", 2},
-		{itemIdentifier, 10, "y", 2},
-		{itemRightDelim, 11, "}}", 2},
-		{itemEOF, 13, "", 2},
-	}},
-	{"trimbefore", "{{x}}\n{{- y}}", []item{
-		{itemLeftDelim, 0, "{{", 1},
-		{itemIdentifier, 2, "x", 1},
-		{itemRightDelim, 3, "}}", 1},
-		{itemLeftDelim, 6, "{{", 2},
-		{itemIdentifier, 10, "y", 2},
-		{itemRightDelim, 11, "}}", 2},
-		{itemEOF, 13, "", 2},
-	}},
-}
-
-// The other tests don't check position, to make the test cases easier to construct.
-// This one does.
-func TestPos(t *testing.T) {
-	for _, test := range lexPosTests {
-		items := collect(&test, "", "")
-		if !equal(items, test.items, true) {
-			t.Errorf("%s: got\n\t%v\nexpected\n\t%v", test.name, items, test.items)
-			if len(items) == len(test.items) {
-				// Detailed print; avoid item.String() to expose the position value.
-				for i := range items {
-					if !equal(items[i:i+1], test.items[i:i+1], true) {
-						i1 := items[i]
-						i2 := test.items[i]
-						t.Errorf("\t#%d: got {%v %d %q %d} expected {%v %d %q %d}",
-							i, i1.typ, i1.pos, i1.val, i1.line, i2.typ, i2.pos, i2.val, i2.line)
-					}
-				}
-			}
-		}
-	}
-}
-
-// Test that an error shuts down the lexing goroutine.
-func TestShutdown(t *testing.T) {
-	// We need to duplicate template.Parse here to hold on to the lexer.
-	const text = "erroneous{{define}}{{else}}1234"
-	lexer := lex("foo", text, "{{", "}}", false)
-	_, err := New("root").parseLexer(lexer)
-	if err == nil {
-		t.Fatalf("expected error")
-	}
-	// The error should have drained the input. Therefore, the lexer should be shut down.
-	token, ok := <-lexer.items
-	if ok {
-		t.Fatalf("input was not drained; got %v", token)
-	}
-}
-
-// parseLexer is a local version of parse that lets us pass in the lexer instead of building it.
-// We expect an error, so the tree set and funcs list are explicitly nil.
-func (t *Tree) parseLexer(lex *lexer) (tree *Tree, err error) {
-	defer t.recover(&err)
-	t.ParseName = t.Name
-	t.startParse(nil, lex, map[string]*Tree{})
-	t.parse()
-	t.add()
-	t.stopParse()
-	return t, nil
-}
diff --git a/go.dev/cmd/internal/text/template/parse/node.go b/go.dev/cmd/internal/text/template/parse/node.go
deleted file mode 100644
index a2da634..0000000
--- a/go.dev/cmd/internal/text/template/parse/node.go
+++ /dev/null
@@ -1,1008 +0,0 @@
-// Copyright 2011 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.
-
-// Parse nodes.
-
-package parse
-
-import (
-	"fmt"
-	"strconv"
-	"strings"
-)
-
-var textFormat = "%s" // Changed to "%q" in tests for better error messages.
-
-// A Node is an element in the parse tree. The interface is trivial.
-// The interface contains an unexported method so that only
-// types local to this package can satisfy it.
-type Node interface {
-	Type() NodeType
-	String() string
-	// Copy does a deep copy of the Node and all its components.
-	// To avoid type assertions, some XxxNodes also have specialized
-	// CopyXxx methods that return *XxxNode.
-	Copy() Node
-	Position() Pos // byte position of start of node in full original input string
-	// tree returns the containing *Tree.
-	// It is unexported so all implementations of Node are in this package.
-	tree() *Tree
-	// writeTo writes the String output to the builder.
-	writeTo(*strings.Builder)
-}
-
-// NodeType identifies the type of a parse tree node.
-type NodeType int
-
-// Pos represents a byte position in the original input text from which
-// this template was parsed.
-type Pos int
-
-func (p Pos) Position() Pos {
-	return p
-}
-
-// Type returns itself and provides an easy default implementation
-// for embedding in a Node. Embedded in all non-trivial Nodes.
-func (t NodeType) Type() NodeType {
-	return t
-}
-
-const (
-	NodeText       NodeType = iota // Plain text.
-	NodeAction                     // A non-control action such as a field evaluation.
-	NodeBool                       // A boolean constant.
-	NodeBreak                      // A break action.
-	NodeChain                      // A sequence of field accesses.
-	NodeCommand                    // An element of a pipeline.
-	NodeContinue                   // A continue action.
-	NodeDot                        // The cursor, dot.
-	nodeElse                       // An else action. Not added to tree.
-	nodeEnd                        // An end action. Not added to tree.
-	NodeField                      // A field or method name.
-	NodeIdentifier                 // An identifier; always a function name.
-	NodeIf                         // An if action.
-	NodeList                       // A list of Nodes.
-	NodeNil                        // An untyped nil constant.
-	NodeNumber                     // A numerical constant.
-	NodePipe                       // A pipeline of commands.
-	NodeRange                      // A range action.
-	NodeString                     // A string constant.
-	NodeTemplate                   // A template invocation action.
-	NodeVariable                   // A $ variable.
-	NodeWith                       // A with action.
-	NodeComment                    // A comment.
-)
-
-// Nodes.
-
-// ListNode holds a sequence of nodes.
-type ListNode struct {
-	NodeType
-	Pos
-	tr    *Tree
-	Nodes []Node // The element nodes in lexical order.
-}
-
-func (t *Tree) newList(pos Pos) *ListNode {
-	return &ListNode{tr: t, NodeType: NodeList, Pos: pos}
-}
-
-func (l *ListNode) append(n Node) {
-	l.Nodes = append(l.Nodes, n)
-}
-
-func (l *ListNode) tree() *Tree {
-	return l.tr
-}
-
-func (l *ListNode) String() string {
-	var sb strings.Builder
-	l.writeTo(&sb)
-	return sb.String()
-}
-
-func (l *ListNode) writeTo(sb *strings.Builder) {
-	for _, n := range l.Nodes {
-		n.writeTo(sb)
-	}
-}
-
-func (l *ListNode) CopyList() *ListNode {
-	if l == nil {
-		return l
-	}
-	n := l.tr.newList(l.Pos)
-	for _, elem := range l.Nodes {
-		n.append(elem.Copy())
-	}
-	return n
-}
-
-func (l *ListNode) Copy() Node {
-	return l.CopyList()
-}
-
-// TextNode holds plain text.
-type TextNode struct {
-	NodeType
-	Pos
-	tr   *Tree
-	Text []byte // The text; may span newlines.
-}
-
-func (t *Tree) newText(pos Pos, text string) *TextNode {
-	return &TextNode{tr: t, NodeType: NodeText, Pos: pos, Text: []byte(text)}
-}
-
-func (t *TextNode) String() string {
-	return fmt.Sprintf(textFormat, t.Text)
-}
-
-func (t *TextNode) writeTo(sb *strings.Builder) {
-	sb.WriteString(t.String())
-}
-
-func (t *TextNode) tree() *Tree {
-	return t.tr
-}
-
-func (t *TextNode) Copy() Node {
-	return &TextNode{tr: t.tr, NodeType: NodeText, Pos: t.Pos, Text: append([]byte{}, t.Text...)}
-}
-
-// CommentNode holds a comment.
-type CommentNode struct {
-	NodeType
-	Pos
-	tr   *Tree
-	Text string // Comment text.
-}
-
-func (t *Tree) newComment(pos Pos, text string) *CommentNode {
-	return &CommentNode{tr: t, NodeType: NodeComment, Pos: pos, Text: text}
-}
-
-func (c *CommentNode) String() string {
-	var sb strings.Builder
-	c.writeTo(&sb)
-	return sb.String()
-}
-
-func (c *CommentNode) writeTo(sb *strings.Builder) {
-	sb.WriteString("{{")
-	sb.WriteString(c.Text)
-	sb.WriteString("}}")
-}
-
-func (c *CommentNode) tree() *Tree {
-	return c.tr
-}
-
-func (c *CommentNode) Copy() Node {
-	return &CommentNode{tr: c.tr, NodeType: NodeComment, Pos: c.Pos, Text: c.Text}
-}
-
-// PipeNode holds a pipeline with optional declaration
-type PipeNode struct {
-	NodeType
-	Pos
-	tr       *Tree
-	Line     int             // The line number in the input. Deprecated: Kept for compatibility.
-	IsAssign bool            // The variables are being assigned, not declared.
-	Decl     []*VariableNode // Variables in lexical order.
-	Cmds     []*CommandNode  // The commands in lexical order.
-}
-
-func (t *Tree) newPipeline(pos Pos, line int, vars []*VariableNode) *PipeNode {
-	return &PipeNode{tr: t, NodeType: NodePipe, Pos: pos, Line: line, Decl: vars}
-}
-
-func (p *PipeNode) append(command *CommandNode) {
-	p.Cmds = append(p.Cmds, command)
-}
-
-func (p *PipeNode) String() string {
-	var sb strings.Builder
-	p.writeTo(&sb)
-	return sb.String()
-}
-
-func (p *PipeNode) writeTo(sb *strings.Builder) {
-	if len(p.Decl) > 0 {
-		for i, v := range p.Decl {
-			if i > 0 {
-				sb.WriteString(", ")
-			}
-			v.writeTo(sb)
-		}
-		sb.WriteString(" := ")
-	}
-	for i, c := range p.Cmds {
-		if i > 0 {
-			sb.WriteString(" | ")
-		}
-		c.writeTo(sb)
-	}
-}
-
-func (p *PipeNode) tree() *Tree {
-	return p.tr
-}
-
-func (p *PipeNode) CopyPipe() *PipeNode {
-	if p == nil {
-		return p
-	}
-	vars := make([]*VariableNode, len(p.Decl))
-	for i, d := range p.Decl {
-		vars[i] = d.Copy().(*VariableNode)
-	}
-	n := p.tr.newPipeline(p.Pos, p.Line, vars)
-	n.IsAssign = p.IsAssign
-	for _, c := range p.Cmds {
-		n.append(c.Copy().(*CommandNode))
-	}
-	return n
-}
-
-func (p *PipeNode) Copy() Node {
-	return p.CopyPipe()
-}
-
-// ActionNode holds an action (something bounded by delimiters).
-// Control actions have their own nodes; ActionNode represents simple
-// ones such as field evaluations and parenthesized pipelines.
-type ActionNode struct {
-	NodeType
-	Pos
-	tr   *Tree
-	Line int       // The line number in the input. Deprecated: Kept for compatibility.
-	Pipe *PipeNode // The pipeline in the action.
-}
-
-func (t *Tree) newAction(pos Pos, line int, pipe *PipeNode) *ActionNode {
-	return &ActionNode{tr: t, NodeType: NodeAction, Pos: pos, Line: line, Pipe: pipe}
-}
-
-func (a *ActionNode) String() string {
-	var sb strings.Builder
-	a.writeTo(&sb)
-	return sb.String()
-}
-
-func (a *ActionNode) writeTo(sb *strings.Builder) {
-	sb.WriteString("{{")
-	a.Pipe.writeTo(sb)
-	sb.WriteString("}}")
-}
-
-func (a *ActionNode) tree() *Tree {
-	return a.tr
-}
-
-func (a *ActionNode) Copy() Node {
-	return a.tr.newAction(a.Pos, a.Line, a.Pipe.CopyPipe())
-
-}
-
-// CommandNode holds a command (a pipeline inside an evaluating action).
-type CommandNode struct {
-	NodeType
-	Pos
-	tr   *Tree
-	Args []Node // Arguments in lexical order: Identifier, field, or constant.
-}
-
-func (t *Tree) newCommand(pos Pos) *CommandNode {
-	return &CommandNode{tr: t, NodeType: NodeCommand, Pos: pos}
-}
-
-func (c *CommandNode) append(arg Node) {
-	c.Args = append(c.Args, arg)
-}
-
-func (c *CommandNode) String() string {
-	var sb strings.Builder
-	c.writeTo(&sb)
-	return sb.String()
-}
-
-func (c *CommandNode) writeTo(sb *strings.Builder) {
-	for i, arg := range c.Args {
-		if i > 0 {
-			sb.WriteByte(' ')
-		}
-		if arg, ok := arg.(*PipeNode); ok {
-			sb.WriteByte('(')
-			arg.writeTo(sb)
-			sb.WriteByte(')')
-			continue
-		}
-		arg.writeTo(sb)
-	}
-}
-
-func (c *CommandNode) tree() *Tree {
-	return c.tr
-}
-
-func (c *CommandNode) Copy() Node {
-	if c == nil {
-		return c
-	}
-	n := c.tr.newCommand(c.Pos)
-	for _, c := range c.Args {
-		n.append(c.Copy())
-	}
-	return n
-}
-
-// IdentifierNode holds an identifier.
-type IdentifierNode struct {
-	NodeType
-	Pos
-	tr    *Tree
-	Ident string // The identifier's name.
-}
-
-// NewIdentifier returns a new IdentifierNode with the given identifier name.
-func NewIdentifier(ident string) *IdentifierNode {
-	return &IdentifierNode{NodeType: NodeIdentifier, Ident: ident}
-}
-
-// SetPos sets the position. NewIdentifier is a public method so we can't modify its signature.
-// Chained for convenience.
-// TODO: fix one day?
-func (i *IdentifierNode) SetPos(pos Pos) *IdentifierNode {
-	i.Pos = pos
-	return i
-}
-
-// SetTree sets the parent tree for the node. NewIdentifier is a public method so we can't modify its signature.
-// Chained for convenience.
-// TODO: fix one day?
-func (i *IdentifierNode) SetTree(t *Tree) *IdentifierNode {
-	i.tr = t
-	return i
-}
-
-func (i *IdentifierNode) String() string {
-	return i.Ident
-}
-
-func (i *IdentifierNode) writeTo(sb *strings.Builder) {
-	sb.WriteString(i.String())
-}
-
-func (i *IdentifierNode) tree() *Tree {
-	return i.tr
-}
-
-func (i *IdentifierNode) Copy() Node {
-	return NewIdentifier(i.Ident).SetTree(i.tr).SetPos(i.Pos)
-}
-
-// VariableNode holds a list of variable names, possibly with chained field
-// accesses. The dollar sign is part of the (first) name.
-type VariableNode struct {
-	NodeType
-	Pos
-	tr    *Tree
-	Ident []string // Variable name and fields in lexical order.
-}
-
-func (t *Tree) newVariable(pos Pos, ident string) *VariableNode {
-	return &VariableNode{tr: t, NodeType: NodeVariable, Pos: pos, Ident: strings.Split(ident, ".")}
-}
-
-func (v *VariableNode) String() string {
-	var sb strings.Builder
-	v.writeTo(&sb)
-	return sb.String()
-}
-
-func (v *VariableNode) writeTo(sb *strings.Builder) {
-	for i, id := range v.Ident {
-		if i > 0 {
-			sb.WriteByte('.')
-		}
-		sb.WriteString(id)
-	}
-}
-
-func (v *VariableNode) tree() *Tree {
-	return v.tr
-}
-
-func (v *VariableNode) Copy() Node {
-	return &VariableNode{tr: v.tr, NodeType: NodeVariable, Pos: v.Pos, Ident: append([]string{}, v.Ident...)}
-}
-
-// DotNode holds the special identifier '.'.
-type DotNode struct {
-	NodeType
-	Pos
-	tr *Tree
-}
-
-func (t *Tree) newDot(pos Pos) *DotNode {
-	return &DotNode{tr: t, NodeType: NodeDot, Pos: pos}
-}
-
-func (d *DotNode) Type() NodeType {
-	// Override method on embedded NodeType for API compatibility.
-	// TODO: Not really a problem; could change API without effect but
-	// api tool complains.
-	return NodeDot
-}
-
-func (d *DotNode) String() string {
-	return "."
-}
-
-func (d *DotNode) writeTo(sb *strings.Builder) {
-	sb.WriteString(d.String())
-}
-
-func (d *DotNode) tree() *Tree {
-	return d.tr
-}
-
-func (d *DotNode) Copy() Node {
-	return d.tr.newDot(d.Pos)
-}
-
-// NilNode holds the special identifier 'nil' representing an untyped nil constant.
-type NilNode struct {
-	NodeType
-	Pos
-	tr *Tree
-}
-
-func (t *Tree) newNil(pos Pos) *NilNode {
-	return &NilNode{tr: t, NodeType: NodeNil, Pos: pos}
-}
-
-func (n *NilNode) Type() NodeType {
-	// Override method on embedded NodeType for API compatibility.
-	// TODO: Not really a problem; could change API without effect but
-	// api tool complains.
-	return NodeNil
-}
-
-func (n *NilNode) String() string {
-	return "nil"
-}
-
-func (n *NilNode) writeTo(sb *strings.Builder) {
-	sb.WriteString(n.String())
-}
-
-func (n *NilNode) tree() *Tree {
-	return n.tr
-}
-
-func (n *NilNode) Copy() Node {
-	return n.tr.newNil(n.Pos)
-}
-
-// FieldNode holds a field (identifier starting with '.').
-// The names may be chained ('.x.y').
-// The period is dropped from each ident.
-type FieldNode struct {
-	NodeType
-	Pos
-	tr    *Tree
-	Ident []string // The identifiers in lexical order.
-}
-
-func (t *Tree) newField(pos Pos, ident string) *FieldNode {
-	return &FieldNode{tr: t, NodeType: NodeField, Pos: pos, Ident: strings.Split(ident[1:], ".")} // [1:] to drop leading period
-}
-
-func (f *FieldNode) String() string {
-	var sb strings.Builder
-	f.writeTo(&sb)
-	return sb.String()
-}
-
-func (f *FieldNode) writeTo(sb *strings.Builder) {
-	for _, id := range f.Ident {
-		sb.WriteByte('.')
-		sb.WriteString(id)
-	}
-}
-
-func (f *FieldNode) tree() *Tree {
-	return f.tr
-}
-
-func (f *FieldNode) Copy() Node {
-	return &FieldNode{tr: f.tr, NodeType: NodeField, Pos: f.Pos, Ident: append([]string{}, f.Ident...)}
-}
-
-// ChainNode holds a term followed by a chain of field accesses (identifier starting with '.').
-// The names may be chained ('.x.y').
-// The periods are dropped from each ident.
-type ChainNode struct {
-	NodeType
-	Pos
-	tr    *Tree
-	Node  Node
-	Field []string // The identifiers in lexical order.
-}
-
-func (t *Tree) newChain(pos Pos, node Node) *ChainNode {
-	return &ChainNode{tr: t, NodeType: NodeChain, Pos: pos, Node: node}
-}
-
-// Add adds the named field (which should start with a period) to the end of the chain.
-func (c *ChainNode) Add(field string) {
-	if len(field) == 0 || field[0] != '.' {
-		panic("no dot in field")
-	}
-	field = field[1:] // Remove leading dot.
-	if field == "" {
-		panic("empty field")
-	}
-	c.Field = append(c.Field, field)
-}
-
-func (c *ChainNode) String() string {
-	var sb strings.Builder
-	c.writeTo(&sb)
-	return sb.String()
-}
-
-func (c *ChainNode) writeTo(sb *strings.Builder) {
-	if _, ok := c.Node.(*PipeNode); ok {
-		sb.WriteByte('(')
-		c.Node.writeTo(sb)
-		sb.WriteByte(')')
-	} else {
-		c.Node.writeTo(sb)
-	}
-	for _, field := range c.Field {
-		sb.WriteByte('.')
-		sb.WriteString(field)
-	}
-}
-
-func (c *ChainNode) tree() *Tree {
-	return c.tr
-}
-
-func (c *ChainNode) Copy() Node {
-	return &ChainNode{tr: c.tr, NodeType: NodeChain, Pos: c.Pos, Node: c.Node, Field: append([]string{}, c.Field...)}
-}
-
-// BoolNode holds a boolean constant.
-type BoolNode struct {
-	NodeType
-	Pos
-	tr   *Tree
-	True bool // The value of the boolean constant.
-}
-
-func (t *Tree) newBool(pos Pos, true bool) *BoolNode {
-	return &BoolNode{tr: t, NodeType: NodeBool, Pos: pos, True: true}
-}
-
-func (b *BoolNode) String() string {
-	if b.True {
-		return "true"
-	}
-	return "false"
-}
-
-func (b *BoolNode) writeTo(sb *strings.Builder) {
-	sb.WriteString(b.String())
-}
-
-func (b *BoolNode) tree() *Tree {
-	return b.tr
-}
-
-func (b *BoolNode) Copy() Node {
-	return b.tr.newBool(b.Pos, b.True)
-}
-
-// NumberNode holds a number: signed or unsigned integer, float, or complex.
-// The value is parsed and stored under all the types that can represent the value.
-// This simulates in a small amount of code the behavior of Go's ideal constants.
-type NumberNode struct {
-	NodeType
-	Pos
-	tr         *Tree
-	IsInt      bool       // Number has an integral value.
-	IsUint     bool       // Number has an unsigned integral value.
-	IsFloat    bool       // Number has a floating-point value.
-	IsComplex  bool       // Number is complex.
-	Int64      int64      // The signed integer value.
-	Uint64     uint64     // The unsigned integer value.
-	Float64    float64    // The floating-point value.
-	Complex128 complex128 // The complex value.
-	Text       string     // The original textual representation from the input.
-}
-
-func (t *Tree) newNumber(pos Pos, text string, typ itemType) (*NumberNode, error) {
-	n := &NumberNode{tr: t, NodeType: NodeNumber, Pos: pos, Text: text}
-	switch typ {
-	case itemCharConstant:
-		rune, _, tail, err := strconv.UnquoteChar(text[1:], text[0])
-		if err != nil {
-			return nil, err
-		}
-		if tail != "'" {
-			return nil, fmt.Errorf("malformed character constant: %s", text)
-		}
-		n.Int64 = int64(rune)
-		n.IsInt = true
-		n.Uint64 = uint64(rune)
-		n.IsUint = true
-		n.Float64 = float64(rune) // odd but those are the rules.
-		n.IsFloat = true
-		return n, nil
-	case itemComplex:
-		// fmt.Sscan can parse the pair, so let it do the work.
-		if _, err := fmt.Sscan(text, &n.Complex128); err != nil {
-			return nil, err
-		}
-		n.IsComplex = true
-		n.simplifyComplex()
-		return n, nil
-	}
-	// Imaginary constants can only be complex unless they are zero.
-	if len(text) > 0 && text[len(text)-1] == 'i' {
-		f, err := strconv.ParseFloat(text[:len(text)-1], 64)
-		if err == nil {
-			n.IsComplex = true
-			n.Complex128 = complex(0, f)
-			n.simplifyComplex()
-			return n, nil
-		}
-	}
-	// Do integer test first so we get 0x123 etc.
-	u, err := strconv.ParseUint(text, 0, 64) // will fail for -0; fixed below.
-	if err == nil {
-		n.IsUint = true
-		n.Uint64 = u
-	}
-	i, err := strconv.ParseInt(text, 0, 64)
-	if err == nil {
-		n.IsInt = true
-		n.Int64 = i
-		if i == 0 {
-			n.IsUint = true // in case of -0.
-			n.Uint64 = u
-		}
-	}
-	// If an integer extraction succeeded, promote the float.
-	if n.IsInt {
-		n.IsFloat = true
-		n.Float64 = float64(n.Int64)
-	} else if n.IsUint {
-		n.IsFloat = true
-		n.Float64 = float64(n.Uint64)
-	} else {
-		f, err := strconv.ParseFloat(text, 64)
-		if err == nil {
-			// If we parsed it as a float but it looks like an integer,
-			// it's a huge number too large to fit in an int. Reject it.
-			if !strings.ContainsAny(text, ".eEpP") {
-				return nil, fmt.Errorf("integer overflow: %q", text)
-			}
-			n.IsFloat = true
-			n.Float64 = f
-			// If a floating-point extraction succeeded, extract the int if needed.
-			if !n.IsInt && float64(int64(f)) == f {
-				n.IsInt = true
-				n.Int64 = int64(f)
-			}
-			if !n.IsUint && float64(uint64(f)) == f {
-				n.IsUint = true
-				n.Uint64 = uint64(f)
-			}
-		}
-	}
-	if !n.IsInt && !n.IsUint && !n.IsFloat {
-		return nil, fmt.Errorf("illegal number syntax: %q", text)
-	}
-	return n, nil
-}
-
-// simplifyComplex pulls out any other types that are represented by the complex number.
-// These all require that the imaginary part be zero.
-func (n *NumberNode) simplifyComplex() {
-	n.IsFloat = imag(n.Complex128) == 0
-	if n.IsFloat {
-		n.Float64 = real(n.Complex128)
-		n.IsInt = float64(int64(n.Float64)) == n.Float64
-		if n.IsInt {
-			n.Int64 = int64(n.Float64)
-		}
-		n.IsUint = float64(uint64(n.Float64)) == n.Float64
-		if n.IsUint {
-			n.Uint64 = uint64(n.Float64)
-		}
-	}
-}
-
-func (n *NumberNode) String() string {
-	return n.Text
-}
-
-func (n *NumberNode) writeTo(sb *strings.Builder) {
-	sb.WriteString(n.String())
-}
-
-func (n *NumberNode) tree() *Tree {
-	return n.tr
-}
-
-func (n *NumberNode) Copy() Node {
-	nn := new(NumberNode)
-	*nn = *n // Easy, fast, correct.
-	return nn
-}
-
-// StringNode holds a string constant. The value has been "unquoted".
-type StringNode struct {
-	NodeType
-	Pos
-	tr     *Tree
-	Quoted string // The original text of the string, with quotes.
-	Text   string // The string, after quote processing.
-}
-
-func (t *Tree) newString(pos Pos, orig, text string) *StringNode {
-	return &StringNode{tr: t, NodeType: NodeString, Pos: pos, Quoted: orig, Text: text}
-}
-
-func (s *StringNode) String() string {
-	return s.Quoted
-}
-
-func (s *StringNode) writeTo(sb *strings.Builder) {
-	sb.WriteString(s.String())
-}
-
-func (s *StringNode) tree() *Tree {
-	return s.tr
-}
-
-func (s *StringNode) Copy() Node {
-	return s.tr.newString(s.Pos, s.Quoted, s.Text)
-}
-
-// endNode represents an {{end}} action.
-// It does not appear in the final parse tree.
-type endNode struct {
-	NodeType
-	Pos
-	tr *Tree
-}
-
-func (t *Tree) newEnd(pos Pos) *endNode {
-	return &endNode{tr: t, NodeType: nodeEnd, Pos: pos}
-}
-
-func (e *endNode) String() string {
-	return "{{end}}"
-}
-
-func (e *endNode) writeTo(sb *strings.Builder) {
-	sb.WriteString(e.String())
-}
-
-func (e *endNode) tree() *Tree {
-	return e.tr
-}
-
-func (e *endNode) Copy() Node {
-	return e.tr.newEnd(e.Pos)
-}
-
-// elseNode represents an {{else}} action. Does not appear in the final tree.
-type elseNode struct {
-	NodeType
-	Pos
-	tr   *Tree
-	Line int // The line number in the input. Deprecated: Kept for compatibility.
-}
-
-func (t *Tree) newElse(pos Pos, line int) *elseNode {
-	return &elseNode{tr: t, NodeType: nodeElse, Pos: pos, Line: line}
-}
-
-func (e *elseNode) Type() NodeType {
-	return nodeElse
-}
-
-func (e *elseNode) String() string {
-	return "{{else}}"
-}
-
-func (e *elseNode) writeTo(sb *strings.Builder) {
-	sb.WriteString(e.String())
-}
-
-func (e *elseNode) tree() *Tree {
-	return e.tr
-}
-
-func (e *elseNode) Copy() Node {
-	return e.tr.newElse(e.Pos, e.Line)
-}
-
-// BranchNode is the common representation of if, range, and with.
-type BranchNode struct {
-	NodeType
-	Pos
-	tr       *Tree
-	Line     int       // The line number in the input. Deprecated: Kept for compatibility.
-	Pipe     *PipeNode // The pipeline to be evaluated.
-	List     *ListNode // What to execute if the value is non-empty.
-	ElseList *ListNode // What to execute if the value is empty (nil if absent).
-}
-
-func (b *BranchNode) String() string {
-	var sb strings.Builder
-	b.writeTo(&sb)
-	return sb.String()
-}
-
-func (b *BranchNode) writeTo(sb *strings.Builder) {
-	name := ""
-	switch b.NodeType {
-	case NodeIf:
-		name = "if"
-	case NodeRange:
-		name = "range"
-	case NodeWith:
-		name = "with"
-	default:
-		panic("unknown branch type")
-	}
-	sb.WriteString("{{")
-	sb.WriteString(name)
-	sb.WriteByte(' ')
-	b.Pipe.writeTo(sb)
-	sb.WriteString("}}")
-	b.List.writeTo(sb)
-	if b.ElseList != nil {
-		sb.WriteString("{{else}}")
-		b.ElseList.writeTo(sb)
-	}
-	sb.WriteString("{{end}}")
-}
-
-func (b *BranchNode) tree() *Tree {
-	return b.tr
-}
-
-func (b *BranchNode) Copy() Node {
-	switch b.NodeType {
-	case NodeIf:
-		return b.tr.newIf(b.Pos, b.Line, b.Pipe, b.List, b.ElseList)
-	case NodeRange:
-		return b.tr.newRange(b.Pos, b.Line, b.Pipe, b.List, b.ElseList)
-	case NodeWith:
-		return b.tr.newWith(b.Pos, b.Line, b.Pipe, b.List, b.ElseList)
-	default:
-		panic("unknown branch type")
-	}
-}
-
-// IfNode represents an {{if}} action and its commands.
-type IfNode struct {
-	BranchNode
-}
-
-func (t *Tree) newIf(pos Pos, line int, pipe *PipeNode, list, elseList *ListNode) *IfNode {
-	return &IfNode{BranchNode{tr: t, NodeType: NodeIf, Pos: pos, Line: line, Pipe: pipe, List: list, ElseList: elseList}}
-}
-
-func (i *IfNode) Copy() Node {
-	return i.tr.newIf(i.Pos, i.Line, i.Pipe.CopyPipe(), i.List.CopyList(), i.ElseList.CopyList())
-}
-
-// BreakNode represents a {{break}} action.
-type BreakNode struct {
-	tr *Tree
-	NodeType
-	Pos
-	Line int
-}
-
-func (t *Tree) newBreak(pos Pos, line int) *BreakNode {
-	return &BreakNode{tr: t, NodeType: NodeBreak, Pos: pos, Line: line}
-}
-
-func (b *BreakNode) Copy() Node                  { return b.tr.newBreak(b.Pos, b.Line) }
-func (b *BreakNode) String() string              { return "{{break}}" }
-func (b *BreakNode) tree() *Tree                 { return b.tr }
-func (b *BreakNode) writeTo(sb *strings.Builder) { sb.WriteString("{{break}}") }
-
-// ContinueNode represents a {{continue}} action.
-type ContinueNode struct {
-	tr *Tree
-	NodeType
-	Pos
-	Line int
-}
-
-func (t *Tree) newContinue(pos Pos, line int) *ContinueNode {
-	return &ContinueNode{tr: t, NodeType: NodeContinue, Pos: pos, Line: line}
-}
-
-func (c *ContinueNode) Copy() Node                  { return c.tr.newContinue(c.Pos, c.Line) }
-func (c *ContinueNode) String() string              { return "{{continue}}" }
-func (c *ContinueNode) tree() *Tree                 { return c.tr }
-func (c *ContinueNode) writeTo(sb *strings.Builder) { sb.WriteString("{{continue}}") }
-
-// RangeNode represents a {{range}} action and its commands.
-type RangeNode struct {
-	BranchNode
-}
-
-func (t *Tree) newRange(pos Pos, line int, pipe *PipeNode, list, elseList *ListNode) *RangeNode {
-	return &RangeNode{BranchNode{tr: t, NodeType: NodeRange, Pos: pos, Line: line, Pipe: pipe, List: list, ElseList: elseList}}
-}
-
-func (r *RangeNode) Copy() Node {
-	return r.tr.newRange(r.Pos, r.Line, r.Pipe.CopyPipe(), r.List.CopyList(), r.ElseList.CopyList())
-}
-
-// WithNode represents a {{with}} action and its commands.
-type WithNode struct {
-	BranchNode
-}
-
-func (t *Tree) newWith(pos Pos, line int, pipe *PipeNode, list, elseList *ListNode) *WithNode {
-	return &WithNode{BranchNode{tr: t, NodeType: NodeWith, Pos: pos, Line: line, Pipe: pipe, List: list, ElseList: elseList}}
-}
-
-func (w *WithNode) Copy() Node {
-	return w.tr.newWith(w.Pos, w.Line, w.Pipe.CopyPipe(), w.List.CopyList(), w.ElseList.CopyList())
-}
-
-// TemplateNode represents a {{template}} action.
-type TemplateNode struct {
-	NodeType
-	Pos
-	tr   *Tree
-	Line int       // The line number in the input. Deprecated: Kept for compatibility.
-	Name string    // The name of the template (unquoted).
-	Pipe *PipeNode // The command to evaluate as dot for the template.
-}
-
-func (t *Tree) newTemplate(pos Pos, line int, name string, pipe *PipeNode) *TemplateNode {
-	return &TemplateNode{tr: t, NodeType: NodeTemplate, Pos: pos, Line: line, Name: name, Pipe: pipe}
-}
-
-func (t *TemplateNode) String() string {
-	var sb strings.Builder
-	t.writeTo(&sb)
-	return sb.String()
-}
-
-func (t *TemplateNode) writeTo(sb *strings.Builder) {
-	sb.WriteString("{{template ")
-	sb.WriteString(strconv.Quote(t.Name))
-	if t.Pipe != nil {
-		sb.WriteByte(' ')
-		t.Pipe.writeTo(sb)
-	}
-	sb.WriteString("}}")
-}
-
-func (t *TemplateNode) tree() *Tree {
-	return t.tr
-}
-
-func (t *TemplateNode) Copy() Node {
-	return t.tr.newTemplate(t.Pos, t.Line, t.Name, t.Pipe.CopyPipe())
-}
diff --git a/go.dev/cmd/internal/text/template/parse/parse.go b/go.dev/cmd/internal/text/template/parse/parse.go
deleted file mode 100644
index d92bed5..0000000
--- a/go.dev/cmd/internal/text/template/parse/parse.go
+++ /dev/null
@@ -1,796 +0,0 @@
-// Copyright 2011 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 parse builds parse trees for templates as defined by text/template
-// and html/template. Clients should use those packages to construct templates
-// rather than this one, which provides shared internal data structures not
-// intended for general use.
-package parse
-
-import (
-	"bytes"
-	"fmt"
-	"runtime"
-	"strconv"
-	"strings"
-)
-
-// Tree is the representation of a single parsed template.
-type Tree struct {
-	Name      string    // name of the template represented by the tree.
-	ParseName string    // name of the top-level template during parsing, for error messages.
-	Root      *ListNode // top-level root of the tree.
-	Mode      Mode      // parsing mode.
-	text      string    // text parsed to create the template (or its parent)
-	// Parsing only; cleared after parse.
-	funcs      []map[string]interface{}
-	lex        *lexer
-	token      [3]item // three-token lookahead for parser.
-	peekCount  int
-	vars       []string // variables defined at the moment.
-	treeSet    map[string]*Tree
-	actionLine int // line of left delim starting action
-	rangeDepth int
-	mode       Mode
-}
-
-// A mode value is a set of flags (or 0). Modes control parser behavior.
-type Mode uint
-
-const (
-	ParseComments Mode = 1 << iota // parse comments and add them to AST
-	SkipFuncCheck                  // do not check that functions are defined
-)
-
-// Copy returns a copy of the Tree. Any parsing state is discarded.
-func (t *Tree) Copy() *Tree {
-	if t == nil {
-		return nil
-	}
-	return &Tree{
-		Name:      t.Name,
-		ParseName: t.ParseName,
-		Root:      t.Root.CopyList(),
-		text:      t.text,
-	}
-}
-
-// Parse returns a map from template name to parse.Tree, created by parsing the
-// templates described in the argument string. The top-level template will be
-// given the specified name. If an error is encountered, parsing stops and an
-// empty map is returned with the error.
-func Parse(name, text, leftDelim, rightDelim string, funcs ...map[string]interface{}) (map[string]*Tree, error) {
-	treeSet := make(map[string]*Tree)
-	t := New(name)
-	t.text = text
-	_, err := t.Parse(text, leftDelim, rightDelim, treeSet, funcs...)
-	return treeSet, err
-}
-
-// next returns the next token.
-func (t *Tree) next() item {
-	if t.peekCount > 0 {
-		t.peekCount--
-	} else {
-		t.token[0] = t.lex.nextItem()
-	}
-	return t.token[t.peekCount]
-}
-
-// backup backs the input stream up one token.
-func (t *Tree) backup() {
-	t.peekCount++
-}
-
-// backup2 backs the input stream up two tokens.
-// The zeroth token is already there.
-func (t *Tree) backup2(t1 item) {
-	t.token[1] = t1
-	t.peekCount = 2
-}
-
-// backup3 backs the input stream up three tokens
-// The zeroth token is already there.
-func (t *Tree) backup3(t2, t1 item) { // Reverse order: we're pushing back.
-	t.token[1] = t1
-	t.token[2] = t2
-	t.peekCount = 3
-}
-
-// peek returns but does not consume the next token.
-func (t *Tree) peek() item {
-	if t.peekCount > 0 {
-		return t.token[t.peekCount-1]
-	}
-	t.peekCount = 1
-	t.token[0] = t.lex.nextItem()
-	return t.token[0]
-}
-
-// nextNonSpace returns the next non-space token.
-func (t *Tree) nextNonSpace() (token item) {
-	for {
-		token = t.next()
-		if token.typ != itemSpace {
-			break
-		}
-	}
-	return token
-}
-
-// peekNonSpace returns but does not consume the next non-space token.
-func (t *Tree) peekNonSpace() item {
-	token := t.nextNonSpace()
-	t.backup()
-	return token
-}
-
-// Parsing.
-
-// New allocates a new parse tree with the given name.
-func New(name string, funcs ...map[string]interface{}) *Tree {
-	return &Tree{
-		Name:  name,
-		funcs: funcs,
-	}
-}
-
-// ErrorContext returns a textual representation of the location of the node in the input text.
-// The receiver is only used when the node does not have a pointer to the tree inside,
-// which can occur in old code.
-func (t *Tree) ErrorContext(n Node) (location, context string) {
-	pos := int(n.Position())
-	tree := n.tree()
-	if tree == nil {
-		tree = t
-	}
-	text := tree.text[:pos]
-	byteNum := strings.LastIndex(text, "\n")
-	if byteNum == -1 {
-		byteNum = pos // On first line.
-	} else {
-		byteNum++ // After the newline.
-		byteNum = pos - byteNum
-	}
-	lineNum := 1 + strings.Count(text, "\n")
-	context = n.String()
-	return fmt.Sprintf("%s:%d:%d", tree.ParseName, lineNum, byteNum), context
-}
-
-// errorf formats the error and terminates processing.
-func (t *Tree) errorf(format string, args ...interface{}) {
-	t.Root = nil
-	format = fmt.Sprintf("template: %s:%d: %s", t.ParseName, t.token[0].line, format)
-	panic(fmt.Errorf(format, args...))
-}
-
-// error terminates processing.
-func (t *Tree) error(err error) {
-	t.errorf("%s", err)
-}
-
-// expect consumes the next token and guarantees it has the required type.
-func (t *Tree) expect(expected itemType, context string) item {
-	token := t.nextNonSpace()
-	if token.typ != expected {
-		t.unexpected(token, context)
-	}
-	return token
-}
-
-// expectOneOf consumes the next token and guarantees it has one of the required types.
-func (t *Tree) expectOneOf(expected1, expected2 itemType, context string) item {
-	token := t.nextNonSpace()
-	if token.typ != expected1 && token.typ != expected2 {
-		t.unexpected(token, context)
-	}
-	return token
-}
-
-// unexpected complains about the token and terminates processing.
-func (t *Tree) unexpected(token item, context string) {
-	if token.typ == itemError {
-		extra := ""
-		if t.actionLine != 0 && t.actionLine != token.line {
-			extra = fmt.Sprintf(" in action started at %s:%d", t.ParseName, t.actionLine)
-			if strings.HasSuffix(token.val, " action") {
-				extra = extra[len(" in action"):] // avoid "action in action"
-			}
-		}
-		t.errorf("%s%s", token, extra)
-	}
-	t.errorf("unexpected %s in %s", token, context)
-}
-
-// recover is the handler that turns panics into returns from the top level of Parse.
-func (t *Tree) recover(errp *error) {
-	e := recover()
-	if e != nil {
-		if _, ok := e.(runtime.Error); ok {
-			panic(e)
-		}
-		if t != nil {
-			t.lex.drain()
-			t.stopParse()
-		}
-		*errp = e.(error)
-	}
-}
-
-// startParse initializes the parser, using the lexer.
-func (t *Tree) startParse(funcs []map[string]interface{}, lex *lexer, treeSet map[string]*Tree) {
-	t.Root = nil
-	t.lex = lex
-	t.vars = []string{"$"}
-	t.funcs = funcs
-	t.treeSet = treeSet
-	lex.breakOK = !t.hasFunction("break")
-	lex.continueOK = !t.hasFunction("continue")
-}
-
-// stopParse terminates parsing.
-func (t *Tree) stopParse() {
-	t.lex = nil
-	t.vars = nil
-	t.funcs = nil
-	t.treeSet = nil
-}
-
-// Parse parses the template definition string to construct a representation of
-// the template for execution. If either action delimiter string is empty, the
-// default ("{{" or "}}") is used. Embedded template definitions are added to
-// the treeSet map.
-func (t *Tree) Parse(text, leftDelim, rightDelim string, treeSet map[string]*Tree, funcs ...map[string]interface{}) (tree *Tree, err error) {
-	defer t.recover(&err)
-	t.ParseName = t.Name
-	emitComment := t.Mode&ParseComments != 0
-	t.startParse(funcs, lex(t.Name, text, leftDelim, rightDelim, emitComment), treeSet)
-	t.text = text
-	t.parse()
-	t.add()
-	t.stopParse()
-	return t, nil
-}
-
-// add adds tree to t.treeSet.
-func (t *Tree) add() {
-	tree := t.treeSet[t.Name]
-	if tree == nil || IsEmptyTree(tree.Root) {
-		t.treeSet[t.Name] = t
-		return
-	}
-	if !IsEmptyTree(t.Root) {
-		t.errorf("template: multiple definition of template %q", t.Name)
-	}
-}
-
-// IsEmptyTree reports whether this tree (node) is empty of everything but space or comments.
-func IsEmptyTree(n Node) bool {
-	switch n := n.(type) {
-	case nil:
-		return true
-	case *ActionNode:
-	case *CommentNode:
-		return true
-	case *IfNode:
-	case *ListNode:
-		for _, node := range n.Nodes {
-			if !IsEmptyTree(node) {
-				return false
-			}
-		}
-		return true
-	case *RangeNode:
-	case *TemplateNode:
-	case *TextNode:
-		return len(bytes.TrimSpace(n.Text)) == 0
-	case *WithNode:
-	default:
-		panic("unknown node: " + n.String())
-	}
-	return false
-}
-
-// parse is the top-level parser for a template, essentially the same
-// as itemList except it also parses {{define}} actions.
-// It runs to EOF.
-func (t *Tree) parse() {
-	t.Root = t.newList(t.peek().pos)
-	for t.peek().typ != itemEOF {
-		if t.peek().typ == itemLeftDelim {
-			delim := t.next()
-			if t.nextNonSpace().typ == itemDefine {
-				newT := New("definition") // name will be updated once we know it.
-				newT.text = t.text
-				newT.Mode = t.Mode
-				newT.ParseName = t.ParseName
-				newT.startParse(t.funcs, t.lex, t.treeSet)
-				newT.parseDefinition()
-				continue
-			}
-			t.backup2(delim)
-		}
-		switch n := t.textOrAction(); n.Type() {
-		case nodeEnd, nodeElse:
-			t.errorf("unexpected %s", n)
-		default:
-			t.Root.append(n)
-		}
-	}
-}
-
-// parseDefinition parses a {{define}} ...  {{end}} template definition and
-// installs the definition in t.treeSet. The "define" keyword has already
-// been scanned.
-func (t *Tree) parseDefinition() {
-	const context = "define clause"
-	name := t.expectOneOf(itemString, itemRawString, context)
-	var err error
-	t.Name, err = strconv.Unquote(name.val)
-	if err != nil {
-		t.error(err)
-	}
-	t.expect(itemRightDelim, context)
-	var end Node
-	t.Root, end = t.itemList()
-	if end.Type() != nodeEnd {
-		t.errorf("unexpected %s in %s", end, context)
-	}
-	t.add()
-	t.stopParse()
-}
-
-// itemList:
-//	textOrAction*
-// Terminates at {{end}} or {{else}}, returned separately.
-func (t *Tree) itemList() (list *ListNode, next Node) {
-	list = t.newList(t.peekNonSpace().pos)
-	for t.peekNonSpace().typ != itemEOF {
-		n := t.textOrAction()
-		switch n.Type() {
-		case nodeEnd, nodeElse:
-			return list, n
-		}
-		list.append(n)
-	}
-	t.errorf("unexpected EOF")
-	return
-}
-
-// textOrAction:
-//	text | comment | action
-func (t *Tree) textOrAction() Node {
-	switch token := t.nextNonSpace(); token.typ {
-	case itemText:
-		return t.newText(token.pos, token.val)
-	case itemLeftDelim:
-		t.actionLine = token.line
-		defer t.clearActionLine()
-		return t.action()
-	case itemComment:
-		return t.newComment(token.pos, token.val)
-	default:
-		t.unexpected(token, "input")
-	}
-	return nil
-}
-
-func (t *Tree) clearActionLine() {
-	t.actionLine = 0
-}
-
-// Action:
-//	control
-//	command ("|" command)*
-// Left delim is past. Now get actions.
-// First word could be a keyword such as range.
-func (t *Tree) action() (n Node) {
-	switch token := t.nextNonSpace(); token.typ {
-	case itemBlock:
-		return t.blockControl()
-	case itemBreak:
-		return t.breakControl(token.pos, token.line)
-	case itemContinue:
-		return t.continueControl(token.pos, token.line)
-	case itemElse:
-		return t.elseControl()
-	case itemEnd:
-		return t.endControl()
-	case itemIf:
-		return t.ifControl()
-	case itemRange:
-		return t.rangeControl()
-	case itemTemplate:
-		return t.templateControl()
-	case itemWith:
-		return t.withControl()
-	}
-	t.backup()
-	token := t.peek()
-	// Do not pop variables; they persist until "end".
-	return t.newAction(token.pos, token.line, t.pipeline("command", itemRightDelim))
-}
-
-// Break:
-//	{{break}}
-// Break keyword is past.
-func (t *Tree) breakControl(pos Pos, line int) Node {
-	if token := t.next(); token.typ != itemRightDelim {
-		t.unexpected(token, "in {{break}}")
-	}
-	if t.rangeDepth == 0 {
-		t.errorf("{{break}} outside {{range}}")
-	}
-	return t.newBreak(pos, line)
-}
-
-// Continue:
-//	{{continue}}
-// Continue keyword is past.
-func (t *Tree) continueControl(pos Pos, line int) Node {
-	if token := t.next(); token.typ != itemRightDelim {
-		t.unexpected(token, "in {{continue}}")
-	}
-	if t.rangeDepth == 0 {
-		t.errorf("{{continue}} outside {{range}}")
-	}
-	return t.newContinue(pos, line)
-}
-
-// Pipeline:
-//	declarations? command ('|' command)*
-func (t *Tree) pipeline(context string, end itemType) (pipe *PipeNode) {
-	token := t.peekNonSpace()
-	pipe = t.newPipeline(token.pos, token.line, nil)
-	// Are there declarations or assignments?
-decls:
-	if v := t.peekNonSpace(); v.typ == itemVariable {
-		t.next()
-		// Since space is a token, we need 3-token look-ahead here in the worst case:
-		// in "$x foo" we need to read "foo" (as opposed to ":=") to know that $x is an
-		// argument variable rather than a declaration. So remember the token
-		// adjacent to the variable so we can push it back if necessary.
-		tokenAfterVariable := t.peek()
-		next := t.peekNonSpace()
-		switch {
-		case next.typ == itemAssign, next.typ == itemDeclare:
-			pipe.IsAssign = next.typ == itemAssign
-			t.nextNonSpace()
-			pipe.Decl = append(pipe.Decl, t.newVariable(v.pos, v.val))
-			t.vars = append(t.vars, v.val)
-		case next.typ == itemChar && next.val == ",":
-			t.nextNonSpace()
-			pipe.Decl = append(pipe.Decl, t.newVariable(v.pos, v.val))
-			t.vars = append(t.vars, v.val)
-			if context == "range" && len(pipe.Decl) < 2 {
-				switch t.peekNonSpace().typ {
-				case itemVariable, itemRightDelim, itemRightParen:
-					// second initialized variable in a range pipeline
-					goto decls
-				default:
-					t.errorf("range can only initialize variables")
-				}
-			}
-			t.errorf("too many declarations in %s", context)
-		case tokenAfterVariable.typ == itemSpace:
-			t.backup3(v, tokenAfterVariable)
-		default:
-			t.backup2(v)
-		}
-	}
-	for {
-		switch token := t.nextNonSpace(); token.typ {
-		case end:
-			// At this point, the pipeline is complete
-			t.checkPipeline(pipe, context)
-			return
-		case itemBool, itemCharConstant, itemComplex, itemDot, itemField, itemIdentifier,
-			itemNumber, itemNil, itemRawString, itemString, itemVariable, itemLeftParen:
-			t.backup()
-			pipe.append(t.command())
-		default:
-			t.unexpected(token, context)
-		}
-	}
-}
-
-func (t *Tree) checkPipeline(pipe *PipeNode, context string) {
-	// Reject empty pipelines
-	if len(pipe.Cmds) == 0 {
-		t.errorf("missing value for %s", context)
-	}
-	// Only the first command of a pipeline can start with a non executable operand
-	for i, c := range pipe.Cmds[1:] {
-		switch c.Args[0].Type() {
-		case NodeBool, NodeDot, NodeNil, NodeNumber, NodeString:
-			// With A|B|C, pipeline stage 2 is B
-			t.errorf("non executable command in pipeline stage %d", i+2)
-		}
-	}
-}
-
-func (t *Tree) parseControl(allowElseIf bool, context string) (pos Pos, line int, pipe *PipeNode, list, elseList *ListNode) {
-	defer t.popVars(len(t.vars))
-	pipe = t.pipeline(context, itemRightDelim)
-	if context == "range" {
-		t.rangeDepth++
-	}
-	var next Node
-	list, next = t.itemList()
-	if context == "range" {
-		t.rangeDepth--
-	}
-	switch next.Type() {
-	case nodeEnd: //done
-	case nodeElse:
-		if allowElseIf {
-			// Special case for "else if". If the "else" is followed immediately by an "if",
-			// the elseControl will have left the "if" token pending. Treat
-			//	{{if a}}_{{else if b}}_{{end}}
-			// as
-			//	{{if a}}_{{else}}{{if b}}_{{end}}{{end}}.
-			// To do this, parse the if as usual and stop at it {{end}}; the subsequent{{end}}
-			// is assumed. This technique works even for long if-else-if chains.
-			// TODO: Should we allow else-if in with and range?
-			if t.peek().typ == itemIf {
-				t.next() // Consume the "if" token.
-				elseList = t.newList(next.Position())
-				elseList.append(t.ifControl())
-				// Do not consume the next item - only one {{end}} required.
-				break
-			}
-		}
-		elseList, next = t.itemList()
-		if next.Type() != nodeEnd {
-			t.errorf("expected end; found %s", next)
-		}
-	}
-	return pipe.Position(), pipe.Line, pipe, list, elseList
-}
-
-// If:
-//	{{if pipeline}} itemList {{end}}
-//	{{if pipeline}} itemList {{else}} itemList {{end}}
-// If keyword is past.
-func (t *Tree) ifControl() Node {
-	return t.newIf(t.parseControl(true, "if"))
-}
-
-// Range:
-//	{{range pipeline}} itemList {{end}}
-//	{{range pipeline}} itemList {{else}} itemList {{end}}
-// Range keyword is past.
-func (t *Tree) rangeControl() Node {
-	r := t.newRange(t.parseControl(false, "range"))
-	return r
-}
-
-// With:
-//	{{with pipeline}} itemList {{end}}
-//	{{with pipeline}} itemList {{else}} itemList {{end}}
-// If keyword is past.
-func (t *Tree) withControl() Node {
-	return t.newWith(t.parseControl(false, "with"))
-}
-
-// End:
-//	{{end}}
-// End keyword is past.
-func (t *Tree) endControl() Node {
-	return t.newEnd(t.expect(itemRightDelim, "end").pos)
-}
-
-// Else:
-//	{{else}}
-// Else keyword is past.
-func (t *Tree) elseControl() Node {
-	// Special case for "else if".
-	peek := t.peekNonSpace()
-	if peek.typ == itemIf {
-		// We see "{{else if ... " but in effect rewrite it to {{else}}{{if ... ".
-		return t.newElse(peek.pos, peek.line)
-	}
-	token := t.expect(itemRightDelim, "else")
-	return t.newElse(token.pos, token.line)
-}
-
-// Block:
-//	{{block stringValue pipeline}}
-// Block keyword is past.
-// The name must be something that can evaluate to a string.
-// The pipeline is mandatory.
-func (t *Tree) blockControl() Node {
-	const context = "block clause"
-
-	token := t.nextNonSpace()
-	name := t.parseTemplateName(token, context)
-	pipe := t.pipeline(context, itemRightDelim)
-
-	block := New(name) // name will be updated once we know it.
-	block.text = t.text
-	block.Mode = t.Mode
-	block.ParseName = t.ParseName
-	block.startParse(t.funcs, t.lex, t.treeSet)
-	var end Node
-	block.Root, end = block.itemList()
-	if end.Type() != nodeEnd {
-		t.errorf("unexpected %s in %s", end, context)
-	}
-	block.add()
-	block.stopParse()
-
-	return t.newTemplate(token.pos, token.line, name, pipe)
-}
-
-// Template:
-//	{{template stringValue pipeline}}
-// Template keyword is past. The name must be something that can evaluate
-// to a string.
-func (t *Tree) templateControl() Node {
-	const context = "template clause"
-	token := t.nextNonSpace()
-	name := t.parseTemplateName(token, context)
-	var pipe *PipeNode
-	if t.nextNonSpace().typ != itemRightDelim {
-		t.backup()
-		// Do not pop variables; they persist until "end".
-		pipe = t.pipeline(context, itemRightDelim)
-	}
-	return t.newTemplate(token.pos, token.line, name, pipe)
-}
-
-func (t *Tree) parseTemplateName(token item, context string) (name string) {
-	switch token.typ {
-	case itemString, itemRawString:
-		s, err := strconv.Unquote(token.val)
-		if err != nil {
-			t.error(err)
-		}
-		name = s
-	default:
-		t.unexpected(token, context)
-	}
-	return
-}
-
-// command:
-//	operand (space operand)*
-// space-separated arguments up to a pipeline character or right delimiter.
-// we consume the pipe character but leave the right delim to terminate the action.
-func (t *Tree) command() *CommandNode {
-	cmd := t.newCommand(t.peekNonSpace().pos)
-	for {
-		t.peekNonSpace() // skip leading spaces.
-		operand := t.operand()
-		if operand != nil {
-			cmd.append(operand)
-		}
-		switch token := t.next(); token.typ {
-		case itemSpace:
-			continue
-		case itemRightDelim, itemRightParen:
-			t.backup()
-		case itemPipe:
-			// nothing here; break loop below
-		default:
-			t.unexpected(token, "operand")
-		}
-		break
-	}
-	if len(cmd.Args) == 0 {
-		t.errorf("empty command")
-	}
-	return cmd
-}
-
-// operand:
-//	term .Field*
-// An operand is a space-separated component of a command,
-// a term possibly followed by field accesses.
-// A nil return means the next item is not an operand.
-func (t *Tree) operand() Node {
-	node := t.term()
-	if node == nil {
-		return nil
-	}
-	if t.peek().typ == itemField {
-		chain := t.newChain(t.peek().pos, node)
-		for t.peek().typ == itemField {
-			chain.Add(t.next().val)
-		}
-		// Compatibility with original API: If the term is of type NodeField
-		// or NodeVariable, just put more fields on the original.
-		// Otherwise, keep the Chain node.
-		// Obvious parsing errors involving literal values are detected here.
-		// More complex error cases will have to be handled at execution time.
-		switch node.Type() {
-		case NodeField:
-			node = t.newField(chain.Position(), chain.String())
-		case NodeVariable:
-			node = t.newVariable(chain.Position(), chain.String())
-		case NodeBool, NodeString, NodeNumber, NodeNil, NodeDot:
-			t.errorf("unexpected . after term %q", node.String())
-		default:
-			node = chain
-		}
-	}
-	return node
-}
-
-// term:
-//	literal (number, string, nil, boolean)
-//	function (identifier)
-//	.
-//	.Field
-//	$
-//	'(' pipeline ')'
-// A term is a simple "expression".
-// A nil return means the next item is not a term.
-func (t *Tree) term() Node {
-	switch token := t.nextNonSpace(); token.typ {
-	case itemIdentifier:
-		checkFunc := t.Mode&SkipFuncCheck == 0
-		if checkFunc && !t.hasFunction(token.val) {
-			t.errorf("function %q not defined", token.val)
-		}
-		return NewIdentifier(token.val).SetTree(t).SetPos(token.pos)
-	case itemDot:
-		return t.newDot(token.pos)
-	case itemNil:
-		return t.newNil(token.pos)
-	case itemVariable:
-		return t.useVar(token.pos, token.val)
-	case itemField:
-		return t.newField(token.pos, token.val)
-	case itemBool:
-		return t.newBool(token.pos, token.val == "true")
-	case itemCharConstant, itemComplex, itemNumber:
-		number, err := t.newNumber(token.pos, token.val, token.typ)
-		if err != nil {
-			t.error(err)
-		}
-		return number
-	case itemLeftParen:
-		return t.pipeline("parenthesized pipeline", itemRightParen)
-	case itemString, itemRawString:
-		s, err := strconv.Unquote(token.val)
-		if err != nil {
-			t.error(err)
-		}
-		return t.newString(token.pos, token.val, s)
-	}
-	t.backup()
-	return nil
-}
-
-// hasFunction reports if a function name exists in the Tree's maps.
-func (t *Tree) hasFunction(name string) bool {
-	for _, funcMap := range t.funcs {
-		if funcMap == nil {
-			continue
-		}
-		if funcMap[name] != nil {
-			return true
-		}
-	}
-	return false
-}
-
-// popVars trims the variable list to the specified length
-func (t *Tree) popVars(n int) {
-	t.vars = t.vars[:n]
-}
-
-// useVar returns a node for a variable reference. It errors if the
-// variable is not defined.
-func (t *Tree) useVar(pos Pos, name string) Node {
-	v := t.newVariable(pos, name)
-	for _, varName := range t.vars {
-		if varName == v.Ident[0] {
-			return v
-		}
-	}
-	t.errorf("undefined variable %q", v.Ident[0])
-	return nil
-}
diff --git a/go.dev/cmd/internal/text/template/parse/parse_test.go b/go.dev/cmd/internal/text/template/parse/parse_test.go
deleted file mode 100644
index c3679a0..0000000
--- a/go.dev/cmd/internal/text/template/parse/parse_test.go
+++ /dev/null
@@ -1,676 +0,0 @@
-// Copyright 2011 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 parse
-
-import (
-	"flag"
-	"fmt"
-	"strings"
-	"testing"
-)
-
-var debug = flag.Bool("debug", false, "show the errors produced by the main tests")
-
-type numberTest struct {
-	text      string
-	isInt     bool
-	isUint    bool
-	isFloat   bool
-	isComplex bool
-	int64
-	uint64
-	float64
-	complex128
-}
-
-var numberTests = []numberTest{
-	// basics
-	{"0", true, true, true, false, 0, 0, 0, 0},
-	{"-0", true, true, true, false, 0, 0, 0, 0}, // check that -0 is a uint.
-	{"73", true, true, true, false, 73, 73, 73, 0},
-	{"7_3", true, true, true, false, 73, 73, 73, 0},
-	{"0b10_010_01", true, true, true, false, 73, 73, 73, 0},
-	{"0B10_010_01", true, true, true, false, 73, 73, 73, 0},
-	{"073", true, true, true, false, 073, 073, 073, 0},
-	{"0o73", true, true, true, false, 073, 073, 073, 0},
-	{"0O73", true, true, true, false, 073, 073, 073, 0},
-	{"0x73", true, true, true, false, 0x73, 0x73, 0x73, 0},
-	{"0X73", true, true, true, false, 0x73, 0x73, 0x73, 0},
-	{"0x7_3", true, true, true, false, 0x73, 0x73, 0x73, 0},
-	{"-73", true, false, true, false, -73, 0, -73, 0},
-	{"+73", true, false, true, false, 73, 0, 73, 0},
-	{"100", true, true, true, false, 100, 100, 100, 0},
-	{"1e9", true, true, true, false, 1e9, 1e9, 1e9, 0},
-	{"-1e9", true, false, true, false, -1e9, 0, -1e9, 0},
-	{"-1.2", false, false, true, false, 0, 0, -1.2, 0},
-	{"1e19", false, true, true, false, 0, 1e19, 1e19, 0},
-	{"1e1_9", false, true, true, false, 0, 1e19, 1e19, 0},
-	{"1E19", false, true, true, false, 0, 1e19, 1e19, 0},
-	{"-1e19", false, false, true, false, 0, 0, -1e19, 0},
-	{"0x_1p4", true, true, true, false, 16, 16, 16, 0},
-	{"0X_1P4", true, true, true, false, 16, 16, 16, 0},
-	{"0x_1p-4", false, false, true, false, 0, 0, 1 / 16., 0},
-	{"4i", false, false, false, true, 0, 0, 0, 4i},
-	{"-1.2+4.2i", false, false, false, true, 0, 0, 0, -1.2 + 4.2i},
-	{"073i", false, false, false, true, 0, 0, 0, 73i}, // not octal!
-	// complex with 0 imaginary are float (and maybe integer)
-	{"0i", true, true, true, true, 0, 0, 0, 0},
-	{"-1.2+0i", false, false, true, true, 0, 0, -1.2, -1.2},
-	{"-12+0i", true, false, true, true, -12, 0, -12, -12},
-	{"13+0i", true, true, true, true, 13, 13, 13, 13},
-	// funny bases
-	{"0123", true, true, true, false, 0123, 0123, 0123, 0},
-	{"-0x0", true, true, true, false, 0, 0, 0, 0},
-	{"0xdeadbeef", true, true, true, false, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0},
-	// character constants
-	{`'a'`, true, true, true, false, 'a', 'a', 'a', 0},
-	{`'\n'`, true, true, true, false, '\n', '\n', '\n', 0},
-	{`'\\'`, true, true, true, false, '\\', '\\', '\\', 0},
-	{`'\''`, true, true, true, false, '\'', '\'', '\'', 0},
-	{`'\xFF'`, true, true, true, false, 0xFF, 0xFF, 0xFF, 0},
-	{`'パ'`, true, true, true, false, 0x30d1, 0x30d1, 0x30d1, 0},
-	{`'\u30d1'`, true, true, true, false, 0x30d1, 0x30d1, 0x30d1, 0},
-	{`'\U000030d1'`, true, true, true, false, 0x30d1, 0x30d1, 0x30d1, 0},
-	// some broken syntax
-	{text: "+-2"},
-	{text: "0x123."},
-	{text: "1e."},
-	{text: "0xi."},
-	{text: "1+2."},
-	{text: "'x"},
-	{text: "'xx'"},
-	{text: "'433937734937734969526500969526500'"}, // Integer too large - issue 10634.
-	// Issue 8622 - 0xe parsed as floating point. Very embarrassing.
-	{"0xef", true, true, true, false, 0xef, 0xef, 0xef, 0},
-}
-
-func TestNumberParse(t *testing.T) {
-	for _, test := range numberTests {
-		// If fmt.Sscan thinks it's complex, it's complex. We can't trust the output
-		// because imaginary comes out as a number.
-		var c complex128
-		typ := itemNumber
-		var tree *Tree
-		if test.text[0] == '\'' {
-			typ = itemCharConstant
-		} else {
-			_, err := fmt.Sscan(test.text, &c)
-			if err == nil {
-				typ = itemComplex
-			}
-		}
-		n, err := tree.newNumber(0, test.text, typ)
-		ok := test.isInt || test.isUint || test.isFloat || test.isComplex
-		if ok && err != nil {
-			t.Errorf("unexpected error for %q: %s", test.text, err)
-			continue
-		}
-		if !ok && err == nil {
-			t.Errorf("expected error for %q", test.text)
-			continue
-		}
-		if !ok {
-			if *debug {
-				fmt.Printf("%s\n\t%s\n", test.text, err)
-			}
-			continue
-		}
-		if n.IsComplex != test.isComplex {
-			t.Errorf("complex incorrect for %q; should be %t", test.text, test.isComplex)
-		}
-		if test.isInt {
-			if !n.IsInt {
-				t.Errorf("expected integer for %q", test.text)
-			}
-			if n.Int64 != test.int64 {
-				t.Errorf("int64 for %q should be %d Is %d", test.text, test.int64, n.Int64)
-			}
-		} else if n.IsInt {
-			t.Errorf("did not expect integer for %q", test.text)
-		}
-		if test.isUint {
-			if !n.IsUint {
-				t.Errorf("expected unsigned integer for %q", test.text)
-			}
-			if n.Uint64 != test.uint64 {
-				t.Errorf("uint64 for %q should be %d Is %d", test.text, test.uint64, n.Uint64)
-			}
-		} else if n.IsUint {
-			t.Errorf("did not expect unsigned integer for %q", test.text)
-		}
-		if test.isFloat {
-			if !n.IsFloat {
-				t.Errorf("expected float for %q", test.text)
-			}
-			if n.Float64 != test.float64 {
-				t.Errorf("float64 for %q should be %g Is %g", test.text, test.float64, n.Float64)
-			}
-		} else if n.IsFloat {
-			t.Errorf("did not expect float for %q", test.text)
-		}
-		if test.isComplex {
-			if !n.IsComplex {
-				t.Errorf("expected complex for %q", test.text)
-			}
-			if n.Complex128 != test.complex128 {
-				t.Errorf("complex128 for %q should be %g Is %g", test.text, test.complex128, n.Complex128)
-			}
-		} else if n.IsComplex {
-			t.Errorf("did not expect complex for %q", test.text)
-		}
-	}
-}
-
-type parseTest struct {
-	name   string
-	input  string
-	ok     bool
-	result string // what the user would see in an error message.
-}
-
-const (
-	noError  = true
-	hasError = false
-)
-
-var parseTests = []parseTest{
-	{"empty", "", noError,
-		``},
-	{"comment", "{{/*\n\n\n*/}}", noError,
-		``},
-	{"spaces", " \t\n", noError,
-		`" \t\n"`},
-	{"text", "some text", noError,
-		`"some text"`},
-	{"emptyAction", "{{}}", hasError,
-		`{{}}`},
-	{"field", "{{.X}}", noError,
-		`{{.X}}`},
-	{"simple command", "{{printf}}", noError,
-		`{{printf}}`},
-	{"$ invocation", "{{$}}", noError,
-		"{{$}}"},
-	{"variable invocation", "{{with $x := 3}}{{$x 23}}{{end}}", noError,
-		"{{with $x := 3}}{{$x 23}}{{end}}"},
-	{"variable with fields", "{{$.I}}", noError,
-		"{{$.I}}"},
-	{"multi-word command", "{{printf `%d` 23}}", noError,
-		"{{printf `%d` 23}}"},
-	{"pipeline", "{{.X|.Y}}", noError,
-		`{{.X | .Y}}`},
-	{"pipeline with decl", "{{$x := .X|.Y}}", noError,
-		`{{$x := .X | .Y}}`},
-	{"nested pipeline", "{{.X (.Y .Z) (.A | .B .C) (.E)}}", noError,
-		`{{.X (.Y .Z) (.A | .B .C) (.E)}}`},
-	{"field applied to parentheses", "{{(.Y .Z).Field}}", noError,
-		`{{(.Y .Z).Field}}`},
-	{"simple if", "{{if .X}}hello{{end}}", noError,
-		`{{if .X}}"hello"{{end}}`},
-	{"if with else", "{{if .X}}true{{else}}false{{end}}", noError,
-		`{{if .X}}"true"{{else}}"false"{{end}}`},
-	{"if with else if", "{{if .X}}true{{else if .Y}}false{{end}}", noError,
-		`{{if .X}}"true"{{else}}{{if .Y}}"false"{{end}}{{end}}`},
-	{"if else chain", "+{{if .X}}X{{else if .Y}}Y{{else if .Z}}Z{{end}}+", noError,
-		`"+"{{if .X}}"X"{{else}}{{if .Y}}"Y"{{else}}{{if .Z}}"Z"{{end}}{{end}}{{end}}"+"`},
-	{"simple range", "{{range .X}}hello{{end}}", noError,
-		`{{range .X}}"hello"{{end}}`},
-	{"chained field range", "{{range .X.Y.Z}}hello{{end}}", noError,
-		`{{range .X.Y.Z}}"hello"{{end}}`},
-	{"nested range", "{{range .X}}hello{{range .Y}}goodbye{{end}}{{end}}", noError,
-		`{{range .X}}"hello"{{range .Y}}"goodbye"{{end}}{{end}}`},
-	{"range with else", "{{range .X}}true{{else}}false{{end}}", noError,
-		`{{range .X}}"true"{{else}}"false"{{end}}`},
-	{"range over pipeline", "{{range .X|.M}}true{{else}}false{{end}}", noError,
-		`{{range .X | .M}}"true"{{else}}"false"{{end}}`},
-	{"range []int", "{{range .SI}}{{.}}{{end}}", noError,
-		`{{range .SI}}{{.}}{{end}}`},
-	{"range 1 var", "{{range $x := .SI}}{{.}}{{end}}", noError,
-		`{{range $x := .SI}}{{.}}{{end}}`},
-	{"range 2 vars", "{{range $x, $y := .SI}}{{.}}{{end}}", noError,
-		`{{range $x, $y := .SI}}{{.}}{{end}}`},
-	{"range with break", "{{range .SI}}{{.}}{{break}}{{end}}", noError,
-		`{{range .SI}}{{.}}{{break}}{{end}}`},
-	{"range with continue", "{{range .SI}}{{.}}{{continue}}{{end}}", noError,
-		`{{range .SI}}{{.}}{{continue}}{{end}}`},
-	{"constants", "{{range .SI 1 -3.2i true false 'a' nil}}{{end}}", noError,
-		`{{range .SI 1 -3.2i true false 'a' nil}}{{end}}`},
-	{"template", "{{template `x`}}", noError,
-		`{{template "x"}}`},
-	{"template with arg", "{{template `x` .Y}}", noError,
-		`{{template "x" .Y}}`},
-	{"with", "{{with .X}}hello{{end}}", noError,
-		`{{with .X}}"hello"{{end}}`},
-	{"with with else", "{{with .X}}hello{{else}}goodbye{{end}}", noError,
-		`{{with .X}}"hello"{{else}}"goodbye"{{end}}`},
-	// Trimming spaces.
-	{"trim left", "x \r\n\t{{- 3}}", noError, `"x"{{3}}`},
-	{"trim right", "{{3 -}}\n\n\ty", noError, `{{3}}"y"`},
-	{"trim left and right", "x \r\n\t{{- 3 -}}\n\n\ty", noError, `"x"{{3}}"y"`},
-	{"trim with extra spaces", "x\n{{-  3   -}}\ny", noError, `"x"{{3}}"y"`},
-	{"comment trim left", "x \r\n\t{{- /* hi */}}", noError, `"x"`},
-	{"comment trim right", "{{/* hi */ -}}\n\n\ty", noError, `"y"`},
-	{"comment trim left and right", "x \r\n\t{{- /* */ -}}\n\n\ty", noError, `"x""y"`},
-	{"block definition", `{{block "foo" .}}hello{{end}}`, noError,
-		`{{template "foo" .}}`},
-
-	{"newline in assignment", "{{ $x \n := \n 1 \n }}", noError, "{{$x := 1}}"},
-	{"newline in empty action", "{{\n}}", hasError, "{{\n}}"},
-	{"newline in pipeline", "{{\n\"x\"\n|\nprintf\n}}", noError, `{{"x" | printf}}`},
-	{"newline in comment", "{{/*\nhello\n*/}}", noError, ""},
-	{"newline in comment", "{{-\n/*\nhello\n*/\n-}}", noError, ""},
-
-	// Errors.
-	{"unclosed action", "hello{{range", hasError, ""},
-	{"unmatched end", "{{end}}", hasError, ""},
-	{"unmatched else", "{{else}}", hasError, ""},
-	{"unmatched else after if", "{{if .X}}hello{{end}}{{else}}", hasError, ""},
-	{"multiple else", "{{if .X}}1{{else}}2{{else}}3{{end}}", hasError, ""},
-	{"missing end", "hello{{range .x}}", hasError, ""},
-	{"missing end after else", "hello{{range .x}}{{else}}", hasError, ""},
-	{"undefined function", "hello{{undefined}}", hasError, ""},
-	{"undefined variable", "{{$x}}", hasError, ""},
-	{"variable undefined after end", "{{with $x := 4}}{{end}}{{$x}}", hasError, ""},
-	{"variable undefined in template", "{{template $v}}", hasError, ""},
-	{"declare with field", "{{with $x.Y := 4}}{{end}}", hasError, ""},
-	{"template with field ref", "{{template .X}}", hasError, ""},
-	{"template with var", "{{template $v}}", hasError, ""},
-	{"invalid punctuation", "{{printf 3, 4}}", hasError, ""},
-	{"multidecl outside range", "{{with $v, $u := 3}}{{end}}", hasError, ""},
-	{"too many decls in range", "{{range $u, $v, $w := 3}}{{end}}", hasError, ""},
-	{"dot applied to parentheses", "{{printf (printf .).}}", hasError, ""},
-	{"adjacent args", "{{printf 3`x`}}", hasError, ""},
-	{"adjacent args with .", "{{printf `x`.}}", hasError, ""},
-	{"extra end after if", "{{if .X}}a{{else if .Y}}b{{end}}{{end}}", hasError, ""},
-	{"break outside range", "{{range .}}{{end}} {{break}}", hasError, ""},
-	{"continue outside range", "{{range .}}{{end}} {{continue}}", hasError, ""},
-	{"break in range else", "{{range .}}{{else}}{{break}}{{end}}", hasError, ""},
-	{"continue in range else", "{{range .}}{{else}}{{continue}}{{end}}", hasError, ""},
-	// Other kinds of assignments and operators aren't available yet.
-	{"bug0a", "{{$x := 0}}{{$x}}", noError, "{{$x := 0}}{{$x}}"},
-	{"bug0b", "{{$x += 1}}{{$x}}", hasError, ""},
-	{"bug0c", "{{$x ! 2}}{{$x}}", hasError, ""},
-	{"bug0d", "{{$x % 3}}{{$x}}", hasError, ""},
-	// Check the parse fails for := rather than comma.
-	{"bug0e", "{{range $x := $y := 3}}{{end}}", hasError, ""},
-	// Another bug: variable read must ignore following punctuation.
-	{"bug1a", "{{$x:=.}}{{$x!2}}", hasError, ""},                     // ! is just illegal here.
-	{"bug1b", "{{$x:=.}}{{$x+2}}", hasError, ""},                     // $x+2 should not parse as ($x) (+2).
-	{"bug1c", "{{$x:=.}}{{$x +2}}", noError, "{{$x := .}}{{$x +2}}"}, // It's OK with a space.
-	// dot following a literal value
-	{"dot after integer", "{{1.E}}", hasError, ""},
-	{"dot after float", "{{0.1.E}}", hasError, ""},
-	{"dot after boolean", "{{true.E}}", hasError, ""},
-	{"dot after char", "{{'a'.any}}", hasError, ""},
-	{"dot after string", `{{"hello".guys}}`, hasError, ""},
-	{"dot after dot", "{{..E}}", hasError, ""},
-	{"dot after nil", "{{nil.E}}", hasError, ""},
-	// Wrong pipeline
-	{"wrong pipeline dot", "{{12|.}}", hasError, ""},
-	{"wrong pipeline number", "{{.|12|printf}}", hasError, ""},
-	{"wrong pipeline string", "{{.|printf|\"error\"}}", hasError, ""},
-	{"wrong pipeline char", "{{12|printf|'e'}}", hasError, ""},
-	{"wrong pipeline boolean", "{{.|true}}", hasError, ""},
-	{"wrong pipeline nil", "{{'c'|nil}}", hasError, ""},
-	{"empty pipeline", `{{printf "%d" ( ) }}`, hasError, ""},
-	// Missing pipeline in block
-	{"block definition", `{{block "foo"}}hello{{end}}`, hasError, ""},
-}
-
-var builtins = map[string]interface{}{
-	"printf":   fmt.Sprintf,
-	"contains": strings.Contains,
-}
-
-func testParse(doCopy bool, t *testing.T) {
-	textFormat = "%q"
-	defer func() { textFormat = "%s" }()
-	for _, test := range parseTests {
-		tmpl, err := New(test.name).Parse(test.input, "", "", make(map[string]*Tree), builtins)
-		switch {
-		case err == nil && !test.ok:
-			t.Errorf("%q: expected error; got none", test.name)
-			continue
-		case err != nil && test.ok:
-			t.Errorf("%q: unexpected error: %v", test.name, err)
-			continue
-		case err != nil && !test.ok:
-			// expected error, got one
-			if *debug {
-				fmt.Printf("%s: %s\n\t%s\n", test.name, test.input, err)
-			}
-			continue
-		}
-		var result string
-		if doCopy {
-			result = tmpl.Root.Copy().String()
-		} else {
-			result = tmpl.Root.String()
-		}
-		if result != test.result {
-			t.Errorf("%s=(%q): got\n\t%v\nexpected\n\t%v", test.name, test.input, result, test.result)
-		}
-	}
-}
-
-func TestParse(t *testing.T) {
-	testParse(false, t)
-}
-
-// Same as TestParse, but we copy the node first
-func TestParseCopy(t *testing.T) {
-	testParse(true, t)
-}
-
-func TestParseWithComments(t *testing.T) {
-	textFormat = "%q"
-	defer func() { textFormat = "%s" }()
-	tests := [...]parseTest{
-		{"comment", "{{/*\n\n\n*/}}", noError, "{{/*\n\n\n*/}}"},
-		{"comment trim left", "x \r\n\t{{- /* hi */}}", noError, `"x"{{/* hi */}}`},
-		{"comment trim right", "{{/* hi */ -}}\n\n\ty", noError, `{{/* hi */}}"y"`},
-		{"comment trim left and right", "x \r\n\t{{- /* */ -}}\n\n\ty", noError, `"x"{{/* */}}"y"`},
-	}
-	for _, test := range tests {
-		t.Run(test.name, func(t *testing.T) {
-			tr := New(test.name)
-			tr.Mode = ParseComments
-			tmpl, err := tr.Parse(test.input, "", "", make(map[string]*Tree))
-			if err != nil {
-				t.Errorf("%q: expected error; got none", test.name)
-			}
-			if result := tmpl.Root.String(); result != test.result {
-				t.Errorf("%s=(%q): got\n\t%v\nexpected\n\t%v", test.name, test.input, result, test.result)
-			}
-		})
-	}
-}
-
-func TestSkipFuncCheck(t *testing.T) {
-	oldTextFormat := textFormat
-	textFormat = "%q"
-	defer func() { textFormat = oldTextFormat }()
-	tr := New("skip func check")
-	tr.Mode = SkipFuncCheck
-	tmpl, err := tr.Parse("{{fn 1 2}}", "", "", make(map[string]*Tree))
-	if err != nil {
-		t.Fatalf("unexpected error: %v", err)
-	}
-	expected := "{{fn 1 2}}"
-	if result := tmpl.Root.String(); result != expected {
-		t.Errorf("got\n\t%v\nexpected\n\t%v", result, expected)
-	}
-}
-
-type isEmptyTest struct {
-	name  string
-	input string
-	empty bool
-}
-
-var isEmptyTests = []isEmptyTest{
-	{"empty", ``, true},
-	{"nonempty", `hello`, false},
-	{"spaces only", " \t\n \t\n", true},
-	{"comment only", "{{/* comment */}}", true},
-	{"definition", `{{define "x"}}something{{end}}`, true},
-	{"definitions and space", "{{define `x`}}something{{end}}\n\n{{define `y`}}something{{end}}\n\n", true},
-	{"definitions and text", "{{define `x`}}something{{end}}\nx\n{{define `y`}}something{{end}}\ny\n", false},
-	{"definition and action", "{{define `x`}}something{{end}}{{if 3}}foo{{end}}", false},
-}
-
-func TestIsEmpty(t *testing.T) {
-	if !IsEmptyTree(nil) {
-		t.Errorf("nil tree is not empty")
-	}
-	for _, test := range isEmptyTests {
-		tree, err := New("root").Parse(test.input, "", "", make(map[string]*Tree), nil)
-		if err != nil {
-			t.Errorf("%q: unexpected error: %v", test.name, err)
-			continue
-		}
-		if empty := IsEmptyTree(tree.Root); empty != test.empty {
-			t.Errorf("%q: expected %t got %t", test.name, test.empty, empty)
-		}
-	}
-}
-
-func TestErrorContextWithTreeCopy(t *testing.T) {
-	tree, err := New("root").Parse("{{if true}}{{end}}", "", "", make(map[string]*Tree), nil)
-	if err != nil {
-		t.Fatalf("unexpected tree parse failure: %v", err)
-	}
-	treeCopy := tree.Copy()
-	wantLocation, wantContext := tree.ErrorContext(tree.Root.Nodes[0])
-	gotLocation, gotContext := treeCopy.ErrorContext(treeCopy.Root.Nodes[0])
-	if wantLocation != gotLocation {
-		t.Errorf("wrong error location want %q got %q", wantLocation, gotLocation)
-	}
-	if wantContext != gotContext {
-		t.Errorf("wrong error location want %q got %q", wantContext, gotContext)
-	}
-}
-
-// All failures, and the result is a string that must appear in the error message.
-var errorTests = []parseTest{
-	// Check line numbers are accurate.
-	{"unclosed1",
-		"line1\n{{",
-		hasError, `unclosed1:2: unclosed action`},
-	{"unclosed2",
-		"line1\n{{define `x`}}line2\n{{",
-		hasError, `unclosed2:3: unclosed action`},
-	{"unclosed3",
-		"line1\n{{\"x\"\n\"y\"\n",
-		hasError, `unclosed3:4: unclosed action started at unclosed3:2`},
-	{"unclosed4",
-		"{{\n\n\n\n\n",
-		hasError, `unclosed4:6: unclosed action started at unclosed4:1`},
-	{"var1",
-		"line1\n{{\nx\n}}",
-		hasError, `var1:3: function "x" not defined`},
-	// Specific errors.
-	{"function",
-		"{{foo}}",
-		hasError, `function "foo" not defined`},
-	{"comment1",
-		"{{/*}}",
-		hasError, `comment1:1: unclosed comment`},
-	{"comment2",
-		"{{/*\nhello\n}}",
-		hasError, `comment2:1: unclosed comment`},
-	{"lparen",
-		"{{.X (1 2 3}}",
-		hasError, `unclosed left paren`},
-	{"rparen",
-		"{{.X 1 2 3 ) }}",
-		hasError, `unexpected ")" in command`},
-	{"rparen2",
-		"{{(.X 1 2 3",
-		hasError, `unclosed action`},
-	{"space",
-		"{{`x`3}}",
-		hasError, `in operand`},
-	{"idchar",
-		"{{a#}}",
-		hasError, `'#'`},
-	{"charconst",
-		"{{'a}}",
-		hasError, `unterminated character constant`},
-	{"stringconst",
-		`{{"a}}`,
-		hasError, `unterminated quoted string`},
-	{"rawstringconst",
-		"{{`a}}",
-		hasError, `unterminated raw quoted string`},
-	{"number",
-		"{{0xi}}",
-		hasError, `number syntax`},
-	{"multidefine",
-		"{{define `a`}}a{{end}}{{define `a`}}b{{end}}",
-		hasError, `multiple definition of template`},
-	{"eof",
-		"{{range .X}}",
-		hasError, `unexpected EOF`},
-	{"variable",
-		// Declare $x so it's defined, to avoid that error, and then check we don't parse a declaration.
-		"{{$x := 23}}{{with $x.y := 3}}{{$x 23}}{{end}}",
-		hasError, `unexpected ":="`},
-	{"multidecl",
-		"{{$a,$b,$c := 23}}",
-		hasError, `too many declarations`},
-	{"undefvar",
-		"{{$a}}",
-		hasError, `undefined variable`},
-	{"wrongdot",
-		"{{true.any}}",
-		hasError, `unexpected . after term`},
-	{"wrongpipeline",
-		"{{12|false}}",
-		hasError, `non executable command in pipeline`},
-	{"emptypipeline",
-		`{{ ( ) }}`,
-		hasError, `missing value for parenthesized pipeline`},
-	{"multilinerawstring",
-		"{{ $v := `\n` }} {{",
-		hasError, `multilinerawstring:2: unclosed action`},
-	{"rangeundefvar",
-		"{{range $k}}{{end}}",
-		hasError, `undefined variable`},
-	{"rangeundefvars",
-		"{{range $k, $v}}{{end}}",
-		hasError, `undefined variable`},
-	{"rangemissingvalue1",
-		"{{range $k,}}{{end}}",
-		hasError, `missing value for range`},
-	{"rangemissingvalue2",
-		"{{range $k, $v := }}{{end}}",
-		hasError, `missing value for range`},
-	{"rangenotvariable1",
-		"{{range $k, .}}{{end}}",
-		hasError, `range can only initialize variables`},
-	{"rangenotvariable2",
-		"{{range $k, 123 := .}}{{end}}",
-		hasError, `range can only initialize variables`},
-}
-
-func TestErrors(t *testing.T) {
-	for _, test := range errorTests {
-		t.Run(test.name, func(t *testing.T) {
-			_, err := New(test.name).Parse(test.input, "", "", make(map[string]*Tree))
-			if err == nil {
-				t.Fatalf("expected error %q, got nil", test.result)
-			}
-			if !strings.Contains(err.Error(), test.result) {
-				t.Fatalf("error %q does not contain %q", err, test.result)
-			}
-		})
-	}
-}
-
-func TestBlock(t *testing.T) {
-	const (
-		input = `a{{block "inner" .}}bar{{.}}baz{{end}}b`
-		outer = `a{{template "inner" .}}b`
-		inner = `bar{{.}}baz`
-	)
-	treeSet := make(map[string]*Tree)
-	tmpl, err := New("outer").Parse(input, "", "", treeSet, nil)
-	if err != nil {
-		t.Fatal(err)
-	}
-	if g, w := tmpl.Root.String(), outer; g != w {
-		t.Errorf("outer template = %q, want %q", g, w)
-	}
-	inTmpl := treeSet["inner"]
-	if inTmpl == nil {
-		t.Fatal("block did not define template")
-	}
-	if g, w := inTmpl.Root.String(), inner; g != w {
-		t.Errorf("inner template = %q, want %q", g, w)
-	}
-}
-
-func TestLineNum(t *testing.T) {
-	const count = 100
-	text := strings.Repeat("{{printf 1234}}\n", count)
-	tree, err := New("bench").Parse(text, "", "", make(map[string]*Tree), builtins)
-	if err != nil {
-		t.Fatal(err)
-	}
-	// Check the line numbers. Each line is an action containing a template, followed by text.
-	// That's two nodes per line.
-	nodes := tree.Root.Nodes
-	for i := 0; i < len(nodes); i += 2 {
-		line := 1 + i/2
-		// Action first.
-		action := nodes[i].(*ActionNode)
-		if action.Line != line {
-			t.Fatalf("line %d: action is line %d", line, action.Line)
-		}
-		pipe := action.Pipe
-		if pipe.Line != line {
-			t.Fatalf("line %d: pipe is line %d", line, pipe.Line)
-		}
-	}
-}
-
-func BenchmarkParseLarge(b *testing.B) {
-	text := strings.Repeat("{{1234}}\n", 10000)
-	for i := 0; i < b.N; i++ {
-		_, err := New("bench").Parse(text, "", "", make(map[string]*Tree), builtins)
-		if err != nil {
-			b.Fatal(err)
-		}
-	}
-}
-
-var sinkv, sinkl string
-
-func BenchmarkVariableString(b *testing.B) {
-	v := &VariableNode{
-		Ident: []string{"$", "A", "BB", "CCC", "THIS_IS_THE_VARIABLE_BEING_PROCESSED"},
-	}
-	b.ResetTimer()
-	b.ReportAllocs()
-	for i := 0; i < b.N; i++ {
-		sinkv = v.String()
-	}
-	if sinkv == "" {
-		b.Fatal("Benchmark was not run")
-	}
-}
-
-func BenchmarkListString(b *testing.B) {
-	text := `
-{{(printf .Field1.Field2.Field3).Value}}
-{{$x := (printf .Field1.Field2.Field3).Value}}
-{{$y := (printf $x.Field1.Field2.Field3).Value}}
-{{$z := $y.Field1.Field2.Field3}}
-{{if contains $y $z}}
-	{{printf "%q" $y}}
-{{else}}
-	{{printf "%q" $x}}
-{{end}}
-{{with $z.Field1 | contains "boring"}}
-	{{printf "%q" . | printf "%s"}}
-{{else}}
-	{{printf "%d %d %d" 11 11 11}}
-	{{printf "%d %d %s" 22 22 $x.Field1.Field2.Field3 | printf "%s"}}
-	{{printf "%v" (contains $z.Field1.Field2 $y)}}
-{{end}}
-`
-	tree, err := New("bench").Parse(text, "", "", make(map[string]*Tree), builtins)
-	if err != nil {
-		b.Fatal(err)
-	}
-	b.ResetTimer()
-	b.ReportAllocs()
-	for i := 0; i < b.N; i++ {
-		sinkl = tree.Root.String()
-	}
-	if sinkl == "" {
-		b.Fatal("Benchmark was not run")
-	}
-}
diff --git a/go.dev/cmd/internal/text/template/template.go b/go.dev/cmd/internal/text/template/template.go
deleted file mode 100644
index 5ba31da..0000000
--- a/go.dev/cmd/internal/text/template/template.go
+++ /dev/null
@@ -1,239 +0,0 @@
-// Copyright 2011 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 template
-
-import (
-	"reflect"
-	"sync"
-
-	"golang.org/x/website/go.dev/cmd/internal/text/template/parse"
-)
-
-// common holds the information shared by related templates.
-type common struct {
-	tmpl   map[string]*Template // Map from name to defined templates.
-	muTmpl sync.RWMutex         // protects tmpl
-	option option
-	// We use two maps, one for parsing and one for execution.
-	// This separation makes the API cleaner since it doesn't
-	// expose reflection to the client.
-	muFuncs    sync.RWMutex // protects parseFuncs and execFuncs
-	parseFuncs FuncMap
-	execFuncs  map[string]reflect.Value
-}
-
-// Template is the representation of a parsed template. The *parse.Tree
-// field is exported only for use by html/template and should be treated
-// as unexported by all other clients.
-type Template struct {
-	name string
-	*parse.Tree
-	*common
-	leftDelim  string
-	rightDelim string
-}
-
-// New allocates a new, undefined template with the given name.
-func New(name string) *Template {
-	t := &Template{
-		name: name,
-	}
-	t.init()
-	return t
-}
-
-// Name returns the name of the template.
-func (t *Template) Name() string {
-	return t.name
-}
-
-// New allocates a new, undefined template associated with the given one and with the same
-// delimiters. The association, which is transitive, allows one template to
-// invoke another with a {{template}} action.
-//
-// Because associated templates share underlying data, template construction
-// cannot be done safely in parallel. Once the templates are constructed, they
-// can be executed in parallel.
-func (t *Template) New(name string) *Template {
-	t.init()
-	nt := &Template{
-		name:       name,
-		common:     t.common,
-		leftDelim:  t.leftDelim,
-		rightDelim: t.rightDelim,
-	}
-	return nt
-}
-
-// init guarantees that t has a valid common structure.
-func (t *Template) init() {
-	if t.common == nil {
-		c := new(common)
-		c.tmpl = make(map[string]*Template)
-		c.parseFuncs = make(FuncMap)
-		c.execFuncs = make(map[string]reflect.Value)
-		t.common = c
-	}
-}
-
-// Clone returns a duplicate of the template, including all associated
-// templates. The actual representation is not copied, but the name space of
-// associated templates is, so further calls to Parse in the copy will add
-// templates to the copy but not to the original. Clone can be used to prepare
-// common templates and use them with variant definitions for other templates
-// by adding the variants after the clone is made.
-func (t *Template) Clone() (*Template, error) {
-	nt := t.copy(nil)
-	nt.init()
-	if t.common == nil {
-		return nt, nil
-	}
-	t.muTmpl.RLock()
-	defer t.muTmpl.RUnlock()
-	for k, v := range t.tmpl {
-		if k == t.name {
-			nt.tmpl[t.name] = nt
-			continue
-		}
-		// The associated templates share nt's common structure.
-		tmpl := v.copy(nt.common)
-		nt.tmpl[k] = tmpl
-	}
-	t.muFuncs.RLock()
-	defer t.muFuncs.RUnlock()
-	for k, v := range t.parseFuncs {
-		nt.parseFuncs[k] = v
-	}
-	for k, v := range t.execFuncs {
-		nt.execFuncs[k] = v
-	}
-	return nt, nil
-}
-
-// copy returns a shallow copy of t, with common set to the argument.
-func (t *Template) copy(c *common) *Template {
-	return &Template{
-		name:       t.name,
-		Tree:       t.Tree,
-		common:     c,
-		leftDelim:  t.leftDelim,
-		rightDelim: t.rightDelim,
-	}
-}
-
-// AddParseTree associates the argument parse tree with the template t, giving
-// it the specified name. If the template has not been defined, this tree becomes
-// its definition. If it has been defined and already has that name, the existing
-// definition is replaced; otherwise a new template is created, defined, and returned.
-func (t *Template) AddParseTree(name string, tree *parse.Tree) (*Template, error) {
-	t.muTmpl.Lock()
-	defer t.muTmpl.Unlock()
-	t.init()
-	nt := t
-	if name != t.name {
-		nt = t.New(name)
-	}
-	// Even if nt == t, we need to install it in the common.tmpl map.
-	if t.associate(nt, tree) || nt.Tree == nil {
-		nt.Tree = tree
-	}
-	return nt, nil
-}
-
-// Templates returns a slice of defined templates associated with t.
-func (t *Template) Templates() []*Template {
-	if t.common == nil {
-		return nil
-	}
-	// Return a slice so we don't expose the map.
-	t.muTmpl.RLock()
-	defer t.muTmpl.RUnlock()
-	m := make([]*Template, 0, len(t.tmpl))
-	for _, v := range t.tmpl {
-		m = append(m, v)
-	}
-	return m
-}
-
-// Delims sets the action delimiters to the specified strings, to be used in
-// subsequent calls to Parse, ParseFiles, or ParseGlob. Nested template
-// definitions will inherit the settings. An empty delimiter stands for the
-// corresponding default: {{ or }}.
-// The return value is the template, so calls can be chained.
-func (t *Template) Delims(left, right string) *Template {
-	t.init()
-	t.leftDelim = left
-	t.rightDelim = right
-	return t
-}
-
-// Funcs adds the elements of the argument map to the template's function map.
-// It must be called before the template is parsed.
-// It panics if a value in the map is not a function with appropriate return
-// type or if the name cannot be used syntactically as a function in a template.
-// It is legal to overwrite elements of the map. The return value is the template,
-// so calls can be chained.
-func (t *Template) Funcs(funcMap FuncMap) *Template {
-	t.init()
-	t.muFuncs.Lock()
-	defer t.muFuncs.Unlock()
-	addValueFuncs(t.execFuncs, funcMap)
-	addFuncs(t.parseFuncs, funcMap)
-	return t
-}
-
-// Lookup returns the template with the given name that is associated with t.
-// It returns nil if there is no such template or the template has no definition.
-func (t *Template) Lookup(name string) *Template {
-	if t.common == nil {
-		return nil
-	}
-	t.muTmpl.RLock()
-	defer t.muTmpl.RUnlock()
-	return t.tmpl[name]
-}
-
-// Parse parses text as a template body for t.
-// Named template definitions ({{define ...}} or {{block ...}} statements) in text
-// define additional templates associated with t and are removed from the
-// definition of t itself.
-//
-// Templates can be redefined in successive calls to Parse.
-// A template definition with a body containing only white space and comments
-// is considered empty and will not replace an existing template's body.
-// This allows using Parse to add new named template definitions without
-// overwriting the main template body.
-func (t *Template) Parse(text string) (*Template, error) {
-	t.init()
-	t.muFuncs.RLock()
-	trees, err := parse.Parse(t.name, text, t.leftDelim, t.rightDelim, t.parseFuncs, builtins())
-	t.muFuncs.RUnlock()
-	if err != nil {
-		return nil, err
-	}
-	// Add the newly parsed trees, including the one for t, into our common structure.
-	for name, tree := range trees {
-		if _, err := t.AddParseTree(name, tree); err != nil {
-			return nil, err
-		}
-	}
-	return t, nil
-}
-
-// associate installs the new template into the group of templates associated
-// with t. The two are already known to share the common structure.
-// The boolean return value reports whether to store this tree as t.Tree.
-func (t *Template) associate(new *Template, tree *parse.Tree) bool {
-	if new.common != t.common {
-		panic("internal error: associate not common")
-	}
-	if old := t.tmpl[new.name]; old != nil && parse.IsEmptyTree(tree.Root) && old.Tree != nil {
-		// If a template by that name exists,
-		// don't replace it with an empty template.
-		return false
-	}
-	t.tmpl[new.name] = new
-	return true
-}
diff --git a/go.dev/cmd/internal/text/template/testdata/file1.tmpl b/go.dev/cmd/internal/text/template/testdata/file1.tmpl
deleted file mode 100644
index febf9d9..0000000
--- a/go.dev/cmd/internal/text/template/testdata/file1.tmpl
+++ /dev/null
@@ -1,2 +0,0 @@
-{{define "x"}}TEXT{{end}}
-{{define "dotV"}}{{.V}}{{end}}
diff --git a/go.dev/cmd/internal/text/template/testdata/file2.tmpl b/go.dev/cmd/internal/text/template/testdata/file2.tmpl
deleted file mode 100644
index 39bf6fb..0000000
--- a/go.dev/cmd/internal/text/template/testdata/file2.tmpl
+++ /dev/null
@@ -1,2 +0,0 @@
-{{define "dot"}}{{.}}{{end}}
-{{define "nested"}}{{template "dot" .}}{{end}}
diff --git a/go.dev/cmd/internal/text/template/testdata/tmpl1.tmpl b/go.dev/cmd/internal/text/template/testdata/tmpl1.tmpl
deleted file mode 100644
index b72b3a3..0000000
--- a/go.dev/cmd/internal/text/template/testdata/tmpl1.tmpl
+++ /dev/null
@@ -1,3 +0,0 @@
-template1
-{{define "x"}}x{{end}}
-{{template "y"}}
diff --git a/go.dev/cmd/internal/text/template/testdata/tmpl2.tmpl b/go.dev/cmd/internal/text/template/testdata/tmpl2.tmpl
deleted file mode 100644
index 16beba6..0000000
--- a/go.dev/cmd/internal/text/template/testdata/tmpl2.tmpl
+++ /dev/null
@@ -1,3 +0,0 @@
-template2
-{{define "y"}}y{{end}}
-{{template "x"}}
diff --git a/go.dev/cmd/internal/tmplfunc/func.go b/go.dev/cmd/internal/tmplfunc/func.go
index 9ea117b..7d20d9b 100644
--- a/go.dev/cmd/internal/tmplfunc/func.go
+++ b/go.dev/cmd/internal/tmplfunc/func.go
@@ -11,10 +11,10 @@
 	"regexp"
 	"strings"
 
-	"golang.org/x/website/go.dev/cmd/internal/text/template/parse"
+	"golang.org/x/website/internal/backport/text/template/parse"
 
-	htmltemplate "golang.org/x/website/go.dev/cmd/internal/html/template"
-	texttemplate "golang.org/x/website/go.dev/cmd/internal/text/template"
+	htmltemplate "golang.org/x/website/internal/backport/html/template"
+	texttemplate "golang.org/x/website/internal/backport/text/template"
 )
 
 var validNameRE = regexp.MustCompile(`\A[_\pL][_\pL\p{Nd}]*\z`)
diff --git a/go.dev/cmd/internal/tmplfunc/tmpl.go b/go.dev/cmd/internal/tmplfunc/tmpl.go
index 8932685..1f115f5 100644
--- a/go.dev/cmd/internal/tmplfunc/tmpl.go
+++ b/go.dev/cmd/internal/tmplfunc/tmpl.go
@@ -84,8 +84,8 @@
 	"io/ioutil"
 	"path/filepath"
 
-	htmltemplate "golang.org/x/website/go.dev/cmd/internal/html/template"
-	texttemplate "golang.org/x/website/go.dev/cmd/internal/text/template"
+	htmltemplate "golang.org/x/website/internal/backport/html/template"
+	texttemplate "golang.org/x/website/internal/backport/text/template"
 )
 
 // A Template is a *template.Template, where template refers to either
diff --git a/go.dev/cmd/internal/tmplfunc/tmplfunc_test.go b/go.dev/cmd/internal/tmplfunc/tmplfunc_test.go
index ee555ad..baa6fd9 100644
--- a/go.dev/cmd/internal/tmplfunc/tmplfunc_test.go
+++ b/go.dev/cmd/internal/tmplfunc/tmplfunc_test.go
@@ -10,8 +10,8 @@
 	"strings"
 	"testing"
 
-	htmltemplate "golang.org/x/website/go.dev/cmd/internal/html/template"
-	texttemplate "golang.org/x/website/go.dev/cmd/internal/text/template"
+	htmltemplate "golang.org/x/website/internal/backport/html/template"
+	texttemplate "golang.org/x/website/internal/backport/text/template"
 )
 
 var tests = []struct {
diff --git a/go.dev/go.mod b/go.dev/go.mod
deleted file mode 100644
index 37706b9..0000000
--- a/go.dev/go.mod
+++ /dev/null
@@ -1,13 +0,0 @@
-module golang.org/x/website/go.dev
-
-go 1.13
-
-require (
-	github.com/google/go-cmp v0.3.1
-	github.com/microcosm-cc/bluemonday v1.0.2
-	github.com/yuin/goldmark v1.2.1
-	google.golang.org/api v0.13.0
-	gopkg.in/yaml.v2 v2.2.2
-	gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
-	rsc.io/rf v0.0.0-20210401221041-ba8df2a1fd6c
-)
diff --git a/go.dev/go.sum b/go.dev/go.sum
deleted file mode 100644
index e2f0231..0000000
--- a/go.dev/go.sum
+++ /dev/null
@@ -1,113 +0,0 @@
-cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
-cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
-cloud.google.com/go v0.38.0 h1:ROfEUZz+Gh5pa62DJWXSaonyu3StP6EA6lPEXPI6mCo=
-cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
-github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
-github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
-github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
-github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
-github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
-github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
-github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
-github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
-github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
-github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
-github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg=
-github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
-github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
-github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
-github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
-github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM=
-github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
-github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
-github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=
-github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
-github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
-github.com/microcosm-cc/bluemonday v1.0.2 h1:5lPfLTTAvAbtS0VqT+94yOtFnGfUWYyx0+iToC3Os3s=
-github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc=
-github.com/yuin/goldmark v1.2.1 h1:ruQGxdhGHe7FWOJPT0mKs5+pD2Xs1Bm/kdGlHO04FmM=
-github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
-go.opencensus.io v0.21.0 h1:mU6zScU4U1YAFPHEHYk+3JC4SY7JxgkqS10ZOSyksNg=
-go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
-golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
-golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
-golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
-golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
-golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
-golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
-golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20201021035429-f5854403a974 h1:IX6qOQeG5uLjB/hjjwjedwfjND0hgjPMMyO1RoIXQNI=
-golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
-golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
-golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
-golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0=
-golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
-golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA=
-golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
-golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
-golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
-golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
-golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20201111224557-41a3a589386c/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
-golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
-google.golang.org/api v0.13.0 h1:Q3Ui3V3/CVinFWFiW39Iw0kMuVrRzYX0wN6OPFp0lTA=
-google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
-google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
-google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
-google.golang.org/appengine v1.5.0 h1:KxkO13IPW4Lslp2bz+KHP2E3gtFlrIGNThxkZQ3g+4c=
-google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
-google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
-google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
-google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
-google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873 h1:nfPFGzJkUDX6uBmpN/pSw7MbOAWegH5QDQuoXFHedLg=
-google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
-google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
-google.golang.org/grpc v1.20.1 h1:Hz2g2wirWK7H0qIIhGIqRGTuMwTE8HEKFnDZZ7lm9NU=
-google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
-gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
-gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
-gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
-gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-rsc.io/rf v0.0.0-20210401221041-ba8df2a1fd6c h1:lZl/oVdEEh5FuRJIt6ms8oLEkycLohVgloElXrnx+uw=
-rsc.io/rf v0.0.0-20210401221041-ba8df2a1fd6c/go.mod h1:4rdFt/SlKutY8W9onF7XZvD3H0hD+Xpz/uodEcQLuM4=
diff --git a/go.mod b/go.mod
index b22ee88..183e016 100644
--- a/go.mod
+++ b/go.mod
@@ -6,10 +6,15 @@
 	cloud.google.com/go v0.58.0 // indirect
 	cloud.google.com/go/datastore v1.2.0
 	github.com/gomodule/redigo v2.0.0+incompatible
+	github.com/google/go-cmp v0.5.5
+	github.com/microcosm-cc/bluemonday v1.0.2
 	github.com/yuin/goldmark v1.2.1
 	golang.org/x/build v0.0.0-20210422214718-6469a76194d9
 	golang.org/x/net v0.0.0-20201110031124-69a78807bb2b
 	golang.org/x/tools v0.1.1-0.20210215123931-123adc86bcb6
-	google.golang.org/api v0.27.0 // indirect
+	google.golang.org/api v0.27.0
 	google.golang.org/genproto v0.0.0-20200617032506-f1bdc9086088 // indirect
+	gopkg.in/yaml.v2 v2.3.0
+	gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
+	rsc.io/rf v0.0.0-20210401221041-ba8df2a1fd6c
 )
diff --git a/go.sum b/go.sum
index 6e68972..3fc15ca 100644
--- a/go.sum
+++ b/go.sum
@@ -237,9 +237,11 @@
 github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
 github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
 github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
+github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
 github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
 github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
 github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
 github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
 github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
 github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
@@ -249,6 +251,8 @@
 github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
 github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
 github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
+github.com/microcosm-cc/bluemonday v1.0.2 h1:5lPfLTTAvAbtS0VqT+94yOtFnGfUWYyx0+iToC3Os3s=
+github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc=
 github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
 github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
 github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
@@ -570,6 +574,7 @@
 golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
 golang.org/x/tools v0.0.0-20200606014950-c42cb6316fb6/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
 golang.org/x/tools v0.0.0-20200612220849-54c614fe050c/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20201111224557-41a3a589386c/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
 golang.org/x/tools v0.1.1-0.20210215123931-123adc86bcb6 h1:GZ5npTh1qUGmauzey32dt41k2308lqvKwwsxdvSQD9g=
 golang.org/x/tools v0.1.1-0.20210215123931-123adc86bcb6/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -665,6 +670,7 @@
 gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
 gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
@@ -679,8 +685,11 @@
 gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
 gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
+gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o=
 honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
@@ -693,6 +702,8 @@
 honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
 rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
 rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
+rsc.io/rf v0.0.0-20210401221041-ba8df2a1fd6c h1:lZl/oVdEEh5FuRJIt6ms8oLEkycLohVgloElXrnx+uw=
+rsc.io/rf v0.0.0-20210401221041-ba8df2a1fd6c/go.mod h1:4rdFt/SlKutY8W9onF7XZvD3H0hD+Xpz/uodEcQLuM4=
 rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
 sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
 sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=