func (t *table) hash(s string) (h1, h2 uint32) {
	h := fnv(t.h0, s)
	h1 = h & t.mask
	h2 = (h >> 16) & t.mask
	return
}
hash returns the two hashes for s.
package main
import (
	"flag"
	"fmt"
	"math/rand"
	"os"
	"sort"
	"strings"
)
func identifier(s string) string {
	b := make([]byte, 0, len(s))
	cap := true
	for _, c := range s {
		if c == '-' {
			cap = true
			continue
		}
		if cap && 'a' <= c && c <= 'z' {
			c -= 'a' - 'A'
		}
		cap = false
		b = append(b, byte(c))
	}
	return string(b)
}
var test = flag.Bool("test", false, "generate table_test.go")
func main() {
	flag.Parse()
	var all []string
	all = append(all, elements...)
	all = append(all, attributes...)
	all = append(all, eventHandlers...)
	all = append(all, extra...)
	sort.Strings(all)
	if *test {
		fmt.Printf("// generated by go run gen.go -test; DO NOT EDIT\n\n")
		fmt.Printf("package atom\n\n")
		fmt.Printf("var testAtomList = []string{\n")
		for _, s := range all {
			fmt.Printf("\t%q,\n", s)
		}
		fmt.Printf("}\n")
		return
	}
	maxLen := 0
	w := 0
	for _, s := range all {
		if w == 0 || all[w-1] != s {
			if maxLen < len(s) {
				maxLen = len(s)
			}
			all[w] = s
			w++
		}
	}
	all = all[:w]
	var best *table
	for i := 0; i < 1000000; i++ {
		if best != nil && 1<<(best.k-1) < len(all) {
			break
		}
		h := rand.Uint32()
		for k := uint(0); k <= 16; k++ {
			if best != nil && k >= best.k {
				break
			}
			var t table
			if t.init(h, k, all) {
				best = &t
				break
			}
		}
	}
	if best == nil {
		fmt.Fprintf(os.Stderr, "failed to construct string table\n")
		os.Exit(1)
	}
	layout := append([]string{}, all...)
	for changed := true; changed; {
		changed = false
		for i, s := range layout {
			if s == "" {
				continue
			}
			for j, t := range layout {
				if i != j && t != "" && strings.Contains(s, t) {
					changed = true
					layout[j] = ""
				}
			}
		}
	}
	for {
		besti := -1
		bestj := -1
		bestk := 0
		for i, s := range layout {
			if s == "" {
				continue
			}
			for j, t := range layout {
				if i == j {
					continue
				}
				for k := bestk + 1; k <= len(s) && k <= len(t); k++ {
					if s[len(s)-k:] == t[:k] {
						besti = i
						bestj = j
						bestk = k
					}
				}
			}
		}
		if bestk > 0 {
			layout[besti] += layout[bestj][bestk:]
			layout[bestj] = ""
			continue
		}
		break
	}
	text := strings.Join(layout, "")
	atom := map[string]uint32{}
	for _, s := range all {
		off := strings.Index(text, s)
		if off < 0 {
			panic("lost string " + s)
		}
		atom[s] = uint32(off<<8 | len(s))
	}
	fmt.Printf("// generated by go run gen.go; DO NOT EDIT\n\n")
	fmt.Printf("package atom\n\nconst (\n")
	for _, s := range all {
		fmt.Printf("\t%s Atom = %#x\n", identifier(s), atom[s])
	}
	fmt.Printf(")\n\n")
	fmt.Printf("const hash0 = %#x\n\n", best.h0)
	fmt.Printf("const maxAtomLen = %d\n\n", maxLen)
	fmt.Printf("var table = [1<<%d]Atom{\n", best.k)
	for i, s := range best.tab {
		if s == "" {
			continue
		}
		fmt.Printf("\t%#x: %#x, // %s\n", i, atom[s], s)
	}
	fmt.Printf("}\n")
	datasize := (1 << best.k) * 4
	fmt.Printf("const atomText =\n")
	textsize := len(text)
	for len(text) > 60 {
		fmt.Printf("\t%q +\n", text[:60])
		text = text[60:]
	}
	fmt.Printf("\t%q\n\n", text)
	fmt.Fprintf(os.Stderr, "%d atoms; %d string bytes + %d tables = %d total data\n", len(all), textsize, datasize, textsize+datasize)
}
type byLen []string
func (x byLen) Less(i, j int) bool { return len(x[i]) > len(x[j]) }
func (x byLen) Swap(i, j int)      { x[i], x[j] = x[j], x[i] }
func (x byLen) Len() int           { return len(x) }
func fnv(h uint32, s string) uint32 {
	for i := 0; i < len(s); i++ {
		h ^= uint32(s[i])
		h *= 16777619
	}
	return h
}
type table struct {
	h0   uint32
	k    uint
	mask uint32
	tab  []string
}