Commit d91b419e authored by Jeromy's avatar Jeromy
Browse files

WIP

parent a40ef343
Additional IP Rights Grant (Patents)
"This implementation" means the copyrightable works distributed by
Google as part of the Go project.
Google hereby grants to You a perpetual, worldwide, non-exclusive,
no-charge, royalty-free, irrevocable (except as stated in this section)
patent license to make, have made, use, offer to sell, sell, import,
transfer and otherwise run, modify and propagate the contents of this
implementation of Go, where such license applies only to those patent
claims, both currently owned or controlled by Google and acquired in
the future, licensable by Google that are necessarily infringed by this
implementation of Go. This grant does not include claims that would be
infringed only as a consequence of further modification of this
implementation. If you or your agent or exclusive licensee institute or
order or agree to the institution of patent litigation against any
entity (including a cross-claim or counterclaim in a lawsuit) alleging
that this implementation of Go or any code incorporated within this
implementation of Go constitutes direct or contributory patent
infringement, or inducement of patent infringement, then any patent
rights granted to you under this License for this implementation of Go
shall terminate as of the date such litigation is filed.
This repository holds supplementary Go libraries for text processing, many involving Unicode.
To submit changes to this repository, see http://golang.org/doc/contribute.html.
// Copyright 2014 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.
//go:generate go run gen.go gen_trieval.go
// Package cases provides general and language-specific case mappers.
package cases
import (
"gx/QmVgdgtv5rUcWWcHvHN1vdGkXi8UNztJ7JuT72YUJgG2ic/go-text/language"
"gx/QmVgdgtv5rUcWWcHvHN1vdGkXi8UNztJ7JuT72YUJgG2ic/go-text/transform"
)
// References:
// - Unicode Reference Manual Chapter 3.13, 4.2, and 5.18.
// - http://www.unicode.org/reports/tr29/
// - http://www.unicode.org/Public/6.3.0/ucd/CaseFolding.txt
// - http://www.unicode.org/Public/6.3.0/ucd/SpecialCasing.txt
// - http://www.unicode.org/Public/6.3.0/ucd/DerivedCoreProperties.txt
// - http://www.unicode.org/Public/6.3.0/ucd/auxiliary/WordBreakProperty.txt
// - http://www.unicode.org/Public/6.3.0/ucd/auxiliary/WordBreakTest.txt
// - http://userguide.icu-project.org/transforms/casemappings
// TODO:
// - Case folding
// - Wide and Narrow?
// - Segmenter option for title casing.
// - ASCII fast paths
// - Encode Soft-Dotted property within trie somehow.
// A Caser transforms given input to a certain case. It implements
// transform.Transformer.
//
// A Caser may be stateful and should therefore not be shared between
// goroutines.
type Caser struct {
t transform.Transformer
}
// Bytes returns a new byte slice with the result of converting b to the case
// form implemented by c.
func (c Caser) Bytes(b []byte) []byte {
b, _, _ = transform.Bytes(c.t, b)
return b
}
// String returns a string with the result of transforming s to the case form
// implemented by c.
func (c Caser) String(s string) string {
s, _, _ = transform.String(c.t, s)
return s
}
// Reset resets the Caser to be reused for new input after a previous call to
// Transform.
func (c Caser) Reset() { c.t.Reset() }
// Transform implements the Transformer interface and transforms the given input
// to the case form implemented by c.
func (c Caser) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
return c.t.Transform(dst, src, atEOF)
}
// Upper returns a Caser for language-specific uppercasing.
func Upper(t language.Tag, opts ...Option) Caser {
return Caser{makeUpper(t, getOpts(opts...))}
}
// Lower returns a Caser for language-specific lowercasing.
func Lower(t language.Tag, opts ...Option) Caser {
return Caser{makeLower(t, getOpts(opts...))}
}
// Title returns a Caser for language-specific title casing. It uses an
// approximation of the default Unicode Word Break algorithm.
func Title(t language.Tag, opts ...Option) Caser {
return Caser{makeTitle(t, getOpts(opts...))}
}
// Fold returns a Caser that implements Unicode case folding.
//
// Folding is like mapping to lowercase without context-dependent mappings. Its
// primary use is for caseless matching. Note that case folding does not
// normalize the input and may not preserve a normal form.
func Fold(t language.Tag, opts ...Option) Caser {
panic("TODO: implement")
}
// An Option is used to modify the behavior of a Caser.
type Option func(o *options)
var (
// NoLower disables the lowercasing of non-leading letters for a title
// caser.
NoLower Option = noLower
// Compact omits mappings in case folding for characters that would grow the
// input.
Compact Option = compact
)
// TODO: option to preserve a normal form, if applicable?
type options struct {
noLower bool
simple bool
// TODO: segmenter, max ignorable, alternative versions, etc.
noFinalSigma bool // Only used for testing.
}
func getOpts(o ...Option) (res options) {
for _, f := range o {
f(&res)
}
return
}
func noLower(o *options) {
o.noLower = true
}
func compact(o *options) {
o.simple = true
}
// Copyright 2014 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 cases
import (
"gx/QmVgdgtv5rUcWWcHvHN1vdGkXi8UNztJ7JuT72YUJgG2ic/go-text/transform"
)
// A context is used for iterating over source bytes, fetching case info and
// writing to a destination buffer.
//
// Casing operations may need more than one rune of context to decide how a rune
// should be cased. Casing implementations should call checkpoint on context
// whenever it is known to be safe to return the runes processed so far.
//
// It is recommended for implementations to not allow for more than 30 case
// ignorables as lookahead (analogous to the limit in norm) and to use state if
// unbounded lookahead is needed for cased runes.
type context struct {
dst, src []byte
atEOF bool
pDst int // pDst points past the last written rune in dst.
pSrc int // pSrc points to the start of the currently scanned rune.
// checkpoints safe to return in Transform, where nDst <= pDst and nSrc <= pSrc.
nDst, nSrc int
err error
sz int // size of current rune
info info // case information of currently scanned rune
// State preserved across calls to Transform.
isMidWord bool // false if next cased letter needs to be title-cased.
}
func (c *context) Reset() {
c.isMidWord = false
}
// ret returns the return values for the Transform method. It checks whether
// there were insufficient bytes in src to complete and introduces an error
// accordingly, if necessary.
func (c *context) ret() (nDst, nSrc int, err error) {
if c.err != nil || c.nSrc == len(c.src) {
return c.nDst, c.nSrc, c.err
}
// This point is only reached by mappers if there was no short destination
// buffer. This means that the source buffer was exhausted and that c.sz was
// set to 0 by next.
if c.atEOF && c.pSrc == len(c.src) {
return c.pDst, c.pSrc, nil
}
return c.nDst, c.nSrc, transform.ErrShortSrc
}
// checkpoint sets the return value buffer points for Transform to the current
// positions.
func (c *context) checkpoint() {
if c.err == nil {
c.nDst, c.nSrc = c.pDst, c.pSrc+c.sz
}
}
// unreadRune causes the last rune read by next to be reread on the next
// invocation of next. Only one unreadRune may be called after a call to next.
func (c *context) unreadRune() {
c.sz = 0
}
func (c *context) next() bool {
c.pSrc += c.sz
if c.pSrc == len(c.src) || c.err != nil {
c.info, c.sz = 0, 0
return false
}
v, sz := trie.lookup(c.src[c.pSrc:])
c.info, c.sz = info(v), sz
if c.sz == 0 {
if c.atEOF {
// A zero size means we have an incomplete rune. If we are atEOF,
// this means it is an illegal rune, which we will consume one
// byte at a time.
c.sz = 1
} else {
c.err = transform.ErrShortSrc
return false
}
}
return true
}
// writeBytes adds bytes to dst.
func (c *context) writeBytes(b []byte) bool {
if len(c.dst)-c.pDst < len(b) {
c.err = transform.ErrShortDst
return false
}
// This loop is faster than using copy.
for _, ch := range b {
c.dst[c.pDst] = ch
c.pDst++
}
return true
}
// writeString writes the given string to dst.
func (c *context) writeString(s string) bool {
if len(c.dst)-c.pDst < len(s) {
c.err = transform.ErrShortDst
return false
}
// This loop is faster than using copy.
for i := 0; i < len(s); i++ {
c.dst[c.pDst] = s[i]
c.pDst++
}
return true
}
// copy writes the current rune to dst.
func (c *context) copy() bool {
return c.writeBytes(c.src[c.pSrc : c.pSrc+c.sz])
}
// copyXOR copies the current rune to dst and modifies it by applying the XOR
// pattern of the case info. It is the responsibility of the caller to ensure
// that this is a rune with a XOR pattern defined.
func (c *context) copyXOR() bool {
if !c.copy() {
return false
}
if c.info&xorIndexBit == 0 {
// Fast path for 6-bit XOR pattern, which covers most cases.
c.dst[c.pDst-1] ^= byte(c.info >> xorShift)
} else {
// Interpret XOR bits as an index.
// TODO: test performance for unrolling this loop. Verify that we have
// at least two bytes and at most three.
idx := c.info >> xorShift
for p := c.pDst - 1; ; p-- {
c.dst[p] ^= xorData[idx]
idx--
if xorData[idx] == 0 {
break
}
}
}
return true
}
// hasPrefix returns true if src[pSrc:] starts with the given string.
func (c *context) hasPrefix(s string) bool {
b := c.src[c.pSrc:]
if len(b) < len(s) {
return false
}
for i, c := range b[:len(s)] {
if c != s[i] {
return false
}
}
return true
}
// caseType returns an info with only the case bits, normalized to either
// cLower, cUpper, cTitle or cUncased.
func (c *context) caseType() info {
cm := c.info & 0x7
if cm < 4 {
return cm
}
if cm >= cXORCase {
// xor the last bit of the rune with the case type bits.
b := c.src[c.pSrc+c.sz-1]
return info(b&1) ^ cm&0x3
}
if cm == cIgnorableCased {
return cLower
}
return cUncased
}
// Copyright 2014 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 cases
import (
"strings"
"testing"
"unicode"
"gx/QmVgdgtv5rUcWWcHvHN1vdGkXi8UNztJ7JuT72YUJgG2ic/go-text/language"
"gx/QmVgdgtv5rUcWWcHvHN1vdGkXi8UNztJ7JuT72YUJgG2ic/go-text/transform"
"gx/QmVgdgtv5rUcWWcHvHN1vdGkXi8UNztJ7JuT72YUJgG2ic/go-text/unicode/norm"
"gx/QmVgdgtv5rUcWWcHvHN1vdGkXi8UNztJ7JuT72YUJgG2ic/go-text/unicode/rangetable"
)
// The following definitions are taken directly from Chapter 3 of The Unicode
// Standard.
func propCased(r rune) bool {
return propLower(r) || propUpper(r) || unicode.IsTitle(r)
}
func propLower(r rune) bool {
return unicode.IsLower(r) || unicode.Is(unicode.Other_Lowercase, r)
}
func propUpper(r rune) bool {
return unicode.IsUpper(r) || unicode.Is(unicode.Other_Uppercase, r)
}
func propIgnore(r rune) bool {
if unicode.In(r, unicode.Mn, unicode.Me, unicode.Cf, unicode.Lm, unicode.Sk) {
return true
}
return caseIgnorable[r]
}
func hasBreakProp(r rune) bool {
// binary search over ranges
lo := 0
hi := len(breakProp)
for lo < hi {
m := lo + (hi-lo)/2
bp := &breakProp[m]
if bp.lo <= r && r <= bp.hi {
return true
}
if r < bp.lo {
hi = m
} else {
lo = m + 1
}
}
return false
}
func contextFromRune(r rune) *context {
c := context{dst: make([]byte, 128), src: []byte(string(r)), atEOF: true}
c.next()
return &c
}
func TestCaseProperties(t *testing.T) {
assigned := rangetable.Assigned(UnicodeVersion)
coreVersion := rangetable.Assigned(unicode.Version)
for r := rune(0); r <= lastRuneForTesting; r++ {
if !unicode.In(r, assigned) || !unicode.In(r, coreVersion) {
continue
}
c := contextFromRune(r)
if got, want := c.info.isCaseIgnorable(), propIgnore(r); got != want {
t.Errorf("caseIgnorable(%U): got %v; want %v (%x)", r, got, want, c.info)
}
// New letters may change case types, but existing case pairings should
// not change. See Case Pair Stability in
// http://unicode.org/policies/stability_policy.html.
if rf := unicode.SimpleFold(r); rf != r && unicode.In(rf, assigned) {
if got, want := c.info.isCased(), propCased(r); got != want {
t.Errorf("cased(%U): got %v; want %v (%x)", r, got, want, c.info)
}
if got, want := c.caseType() == cUpper, propUpper(r); got != want {
t.Errorf("upper(%U): got %v; want %v (%x)", r, got, want, c.info)
}
if got, want := c.caseType() == cLower, propLower(r); got != want {
t.Errorf("lower(%U): got %v; want %v (%x)", r, got, want, c.info)
}
}
if got, want := c.info.isBreak(), hasBreakProp(r); got != want {
t.Errorf("isBreak(%U): got %v; want %v (%x)", r, got, want, c.info)
}
}
// TODO: get title case from unicode file.
}
func TestMapping(t *testing.T) {
assigned := rangetable.Assigned(UnicodeVersion)
coreVersion := rangetable.Assigned(unicode.Version)
apply := func(r rune, f func(c *context) bool) string {
c := contextFromRune(r)
f(c)
return string(c.dst[:c.pDst])
}
for r, tt := range special {
if got, want := apply(r, lower), tt.toLower; got != want {
t.Errorf("lowerSpecial:(%U): got %+q; want %+q", r, got, want)
}
if got, want := apply(r, title), tt.toTitle; got != want {
t.Errorf("titleSpecial:(%U): got %+q; want %+q", r, got, want)
}
if got, want := apply(r, upper), tt.toUpper; got != want {
t.Errorf("upperSpecial:(%U): got %+q; want %+q", r, got, want)
}
}
for r := rune(0); r <= lastRuneForTesting; r++ {
if !unicode.In(r, assigned) || !unicode.In(r, coreVersion) {
continue
}
if rf := unicode.SimpleFold(r); rf == r || !unicode.In(rf, assigned) {
continue
}
if _, ok := special[r]; ok {
continue
}
want := string(unicode.ToLower(r))
if got := apply(r, lower); got != want {
t.Errorf("lower:%q (%U): got %q %U; want %q %U", r, r, got, []rune(got), want, []rune(want))
}
want = string(unicode.ToUpper(r))
if got := apply(r, upper); got != want {
t.Errorf("upper:%q (%U): got %q %U; want %q %U", r, r, got, []rune(got), want, []rune(want))
}
want = string(unicode.ToTitle(r))
if got := apply(r, title); got != want {
t.Errorf("title:%q (%U): got %q %U; want %q %U", r, r, got, []rune(got), want, []rune(want))
}
}
}
func TestCCC(t *testing.T) {
assigned := rangetable.Assigned(UnicodeVersion)
normVersion := rangetable.Assigned(norm.Version)
for r := rune(0); r <= lastRuneForTesting; r++ {
if !unicode.In(r, assigned) || !unicode.In(r, normVersion) {
continue
}
c := contextFromRune(r)
p := norm.NFC.PropertiesString(string(r))
want := cccOther
switch p.CCC() {
case 0:
want = cccZero
case above:
want = cccAbove
}
if got := c.info.cccType(); got != want {
t.Errorf("%U: got %x; want %x", r, got, want)
}
}
}
func TestWordBreaks(t *testing.T) {
for i, tt := range breakTest {
parts := strings.Split(tt, "|")
want := ""
for _, s := range parts {
want += Title(language.Und).String(s)
}
src := strings.Join(parts, "")
got := Title(language.Und).String(src)
if got != want {
t.Errorf("%d: title(%q) = %q; want %q", i, src, got, want)
}
}
}
func TestContext(t *testing.T) {
tests := []struct {
desc string
dstSize int
atEOF bool
src string
out string
nSrc int
err error
ops string
prefixArg string
prefixWant bool
}{{
desc: "next: past end, atEOF, no checkpoint",
dstSize: 10,
atEOF: true,
src: "12",
out: "",
nSrc: 2,
ops: "next;next;next",
// Test that calling prefix with a non-empty argument when the buffer
// is depleted returns false.
prefixArg: "x",
prefixWant: false,
}, {
desc: "next: not at end, atEOF, no checkpoint",
dstSize: 10,
atEOF: false,
src: "12",
out: "",
nSrc: 0,
err: transform.ErrShortSrc,
ops: "next;next",
prefixArg: "",
prefixWant: true,
}, {
desc: "next: past end, !atEOF, no checkpoint",
dstSize: 10,
atEOF: false,
src: "12",
out: "",
nSrc: 0,
err: transform.ErrShortSrc,
ops: "next;next;next",
prefixArg: "",
prefixWant: true,
}, {
desc: "next: past end, !atEOF, checkpoint",
dstSize: 10,
atEOF: false,
src: "12",
out: "",
nSrc: 2,
ops: "next;next;checkpoint;next",
prefixArg: "",
prefixWant: true,
}, {
desc: "copy: exact count, atEOF, no checkpoint",
dstSize: 2,
atEOF: true,
src: "12",
out: "12",
nSrc: 2,
ops: "next;copy;next;copy;next",
prefixArg: "",
prefixWant: true,
}, {
desc: "copy: past end, !atEOF, no checkpoint",
dstSize: 2,
atEOF: false,
src: "12",
out: "",
nSrc: 0,
err: transform.ErrShortSrc,
ops: "next;copy;next;copy;next",
prefixArg: "",
prefixWant: true,
}, {
desc: "copy: past end, !atEOF, checkpoint",
dstSize: 2,
atEOF: false,
src: "12",
out: "12",
nSrc: 2,
ops: "next;copy;next;copy;checkpoint;next",
prefixArg: "",
prefixWant: true,
}, {
desc: "copy: short dst",
dstSize: 1,
atEOF: false,
src: "12",
out: "",
nSrc: 0,
err: transform.ErrShortDst,
ops: "next;copy;next;copy;checkpoint;next",
prefixArg: "12",
prefixWant: false,
}, {
desc: "copy: short dst, checkpointed",
dstSize: 1,
atEOF: false,
src: "12",
out: "1",
nSrc: 1,
err: transform.ErrShortDst,
ops: "next;copy;checkpoint;next;copy;next",
prefixArg: "",
prefixWant: true,
}, {
desc: "writeString: simple",
dstSize: 3,
atEOF: true,
src: "1",
out: "1ab",
nSrc: 1,
ops: "next;copy;writeab;next",
prefixArg: "",
prefixWant: true,
}, {
desc: "writeString: short dst",
dstSize: 2,
atEOF: true,
src: "12",
out: "",
nSrc: 0,
err: transform.ErrShortDst,
ops: "next;copy;writeab;next",
prefixArg: "2",
prefixWant: true,
}, {
desc: "writeString: simple",
dstSize: 3,
atEOF: true,
src: "12",
out: "1ab",
nSrc: 2,
ops: "next;copy;next;writeab;next",
prefixArg: "",
prefixWant: true,
}, {
desc: "writeString: short dst",
dstSize: 2,
atEOF: true,
src: "12",
out: "",
nSrc: 0,
err: transform.ErrShortDst,
ops: "next;copy;next;writeab;next",
prefixArg: "1",
prefixWant: false,
}, {
desc: "prefix",
dstSize: 2,
atEOF: true,
src: "12",
out: "",
nSrc: 0,
// Context will assign an ErrShortSrc if the input wasn't exhausted.
err: transform.ErrShortSrc,
prefixArg: "12",
prefixWant: true,
}}
for _, tt := range tests {
c := context{dst: make([]byte, tt.dstSize), src: []byte(tt.src), atEOF: tt.atEOF}
for _, op := range strings.Split(tt.ops, ";") {
switch op {
case "next":
c.next()
case "checkpoint":
c.checkpoint()
case "writeab":
c.writeString("ab")
case "copy":
c.copy()
case "":
default:
t.Fatalf("unknown op %q", op)
}
}
if got := c.hasPrefix(tt.prefixArg); got != tt.prefixWant {
t.Errorf("%s:\nprefix was %v; want %v", tt.desc, got, tt.prefixWant)
}
nDst, nSrc, err := c.ret()
if err != tt.err {
t.Errorf("%s:\nerror was %v; want %v", tt.desc, err, tt.err)
}
if out := string(c.dst[:nDst]); out != tt.out {
t.Errorf("%s:\nout was %q; want %q", tt.desc, out, tt.out)
}
if nSrc != tt.nSrc {
t.Errorf("%s:\nnSrc was %d; want %d", tt.desc, nSrc, tt.nSrc)
}
}
}
// Copyright 2014 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 cases_test
import (
"fmt"
"gx/QmVgdgtv5rUcWWcHvHN1vdGkXi8UNztJ7JuT72YUJgG2ic/go-text/cases"
"gx/QmVgdgtv5rUcWWcHvHN1vdGkXi8UNztJ7JuT72YUJgG2ic/go-text/language"
)
func Example() {
src := []string{
"hello world!",
"i with dot",
"'n ijsberg",
"here comes O'Brian",
}
for _, c := range []cases.Caser{
cases.Lower(language.Und),
cases.Upper(language.Turkish),
cases.Title(language.Dutch),
cases.Title(language.Und, cases.NoLower),
} {
fmt.Println()
for _, s := range src {
fmt.Println(c.String(s))
}
}
// Output:
// hello world!
// i with dot
// 'n ijsberg
// here comes o'brian
//
// HELLO WORLD!
// İ WİTH DOT
// 'N İJSBERG
// HERE COMES O'BRİAN
//
// Hello World!
// I With Dot
// 'n IJsberg
// Here Comes O'brian
//
// Hello World!
// I With Dot
// 'N Ijsberg
// Here Comes O'Brian
}
// Copyright 2014 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.
// +build ignore
// This program generates the trie for casing operations. The Unicode casing
// algorithm requires the lookup of various properties and mappings for each
// rune. The table generated by this generator combines several of the most
// frequently used of these into a single trie so that they can be accessed
// with a single lookup.
package main
import (
"bytes"
"fmt"
"io"
"io/ioutil"
"log"
"reflect"
"strconv"
"strings"
"unicode"
"golang.org/x/text/internal/gen"
"golang.org/x/text/internal/triegen"
"golang.org/x/text/internal/ucd"
"golang.org/x/text/unicode/norm"
)
func main() {
gen.Init()
genTables()
genTablesTest()
genTrieval()
}
// runeInfo contains all information for a rune that we care about for casing
// operations.
type runeInfo struct {
Rune rune
entry info // trie value for this rune.
CaseMode info
// Simple case mappings.
Simple [1 + maxCaseMode][]rune
// Special casing
HasSpecial bool
Conditional bool
Special [1 + maxCaseMode][]rune
// Folding (TODO)
FoldSimple rune
FoldSpecial rune
FoldFull []rune
// TODO: FC_NFKC, or equivalent data.
// Properties
SoftDotted bool
CaseIgnorable bool
Cased bool
DecomposeGreek bool
BreakType string
BreakCat breakCategory
// We care mostly about 0, Above, and IotaSubscript.
CCC byte
}
type breakCategory int
const (
breakBreak breakCategory = iota
breakLetter
breakIgnored
)
// mapping returns the case mapping for the given case type.
func (r *runeInfo) mapping(c info) string {
if r.HasSpecial {
return string(r.Special[c])
}
if len(r.Simple[c]) != 0 {
return string(r.Simple[c])
}
return string(r.Rune)
}
// ucdParser is a parser for UCD files.
type ucdParser []ucd.Option
func parser(opts ...ucd.Option) ucdParser { return ucdParser(opts) }
// parse calls f for each entry in the given UCD file.
func (opts ucdParser) parse(filename string, f func(p *ucd.Parser)) {
r := gen.OpenUCDFile(filename)
defer r.Close()
p := ucd.New(r, opts...)
for p.Next() {
f(p)
}
if err := p.Err(); err != nil {
log.Fatal(err)
}
}
func parseUCD() []runeInfo {
chars := make([]runeInfo, unicode.MaxRune)
get := func(r rune) *runeInfo {
c := &chars[r]
c.Rune = r
return c
}
parser().parse("UnicodeData.txt", func(p *ucd.Parser) {
ri := get(p.Rune(0))
ri.CCC = byte(p.Int(ucd.CanonicalCombiningClass))
ri.Simple[cLower] = p.Runes(ucd.SimpleLowercaseMapping)
ri.Simple[cUpper] = p.Runes(ucd.SimpleUppercaseMapping)
ri.Simple[cTitle] = p.Runes(ucd.SimpleTitlecaseMapping)
if p.String(ucd.GeneralCategory) == "Lt" {
ri.CaseMode = cTitle
}
})
// <code>; <property>
parser().parse("PropList.txt", func(p *ucd.Parser) {
if p.String(1) == "Soft_Dotted" {
chars[p.Rune(0)].SoftDotted = true
}
})
// <code>; <word break type>
parser().parse("DerivedCoreProperties.txt", func(p *ucd.Parser) {
ri := get(p.Rune(0))
switch p.String(1) {
case "Case_Ignorable":
ri.CaseIgnorable = true
case "Cased":
ri.Cased = true
case "Lowercase":
ri.CaseMode = cLower
case "Uppercase":
ri.CaseMode = cUpper
}
})
// <code>; <lower> ; <title> ; <upper> ; (<condition_list> ;)?
parser().parse("SpecialCasing.txt", func(p *ucd.Parser) {
// We drop all conditional special casing and deal with them manually in
// the language-specific case mappers. Rune 0x03A3 is the only one with
// a conditional formatting that is not language-specific. However,
// dealing with this letter is tricky, especially in a streaming
// context, so we deal with it in the Caser for Greek specifically.
ri := get(p.Rune(0))
if p.String(4) == "" {
ri.HasSpecial = true
ri.Special[cLower] = p.Runes(1)
ri.Special[cTitle] = p.Runes(2)
ri.Special[cUpper] = p.Runes(3)
} else {
ri.Conditional = true
}
})
// TODO: Use text breaking according to UAX #29.
// <code>; <word break type>
parser().parse("auxiliary/WordBreakProperty.txt", func(p *ucd.Parser) {
ri := get(p.Rune(0))
ri.BreakType = p.String(1)
// We collapse the word breaking properties onto the categories we need.
switch p.String(1) { // TODO: officially we need to canonicalize.
case "Format", "MidLetter", "MidNumLet", "Single_Quote":
ri.BreakCat = breakIgnored
case "ALetter", "Hebrew_Letter", "Numeric", "Extend", "ExtendNumLet":
ri.BreakCat = breakLetter
}
})
// TODO: Support case folding.
// // <code>; <status>; <mapping>;
// parser().parse("CaseFolding.txt", func (p *ucd.Parser) {
// ri := get(p.Rune(0))
// switch p.String(1) {
// case "C":
// ri.FoldSimple = p.Rune(2)
// ri.FoldFull = p.Runes(2)
// case "S":
// ri.FoldSimple = p.Rune(2)
// case "T":
// ri.FoldSpecial = p.Rune(2)
// case "F":
// ri.FoldFull = p.Runes(2)
// }
// })
return chars
}
func genTables() {
chars := parseUCD()
verifyProperties(chars)
t := triegen.NewTrie("case")
for i := range chars {
c := &chars[i]
makeEntry(c)
t.Insert(rune(i), uint64(c.entry))
}
w := &bytes.Buffer{}
sz, err := t.Gen(w, triegen.Compact(&sparseCompacter{}))
if err != nil {
log.Fatal(err)
}
gen.WriteUnicodeVersion(w)
// TODO: write CLDR version after adding a mechanism to detect that the
// tables on which the manually created locale-sensitive casing code is
// based hasn't changed.
fmt.Fprintf(w, "// xorData: %d bytes\n", len(xorData))
fmt.Fprintf(w, "var xorData = %+q\n\n", string(xorData))
fmt.Fprintf(w, "// exceptions: %d bytes\n", len(exceptionData))
fmt.Fprintf(w, "var exceptions = %q\n\n", string(exceptionData))
sz += len(exceptionData)
fmt.Fprintf(w, "// Total table size %d bytes (%dKiB)\n", sz, sz/1024)
gen.WriteGoFile("tables.go", "cases", w.Bytes())
}
func makeEntry(ri *runeInfo) {
if ri.CaseIgnorable {
if ri.Cased {
ri.entry = cIgnorableCased
} else {
ri.entry = cIgnorableUncased
}
} else {
ri.entry = ri.CaseMode
}
// TODO: handle soft-dotted.
ccc := cccOther
switch ri.CCC {
case 0: // Not_Reordered
ccc = cccZero
case above: // Above
ccc = cccAbove
}
if ri.BreakCat == breakBreak {
ccc = cccBreak
}
ri.entry |= ccc
if ri.CaseMode == cUncased {
return
}
// Need to do something special.
if ri.CaseMode == cTitle || ri.HasSpecial || ri.mapping(cTitle) != ri.mapping(cUpper) {
makeException(ri)
return
}
// Rune is either lowercase or uppercase.
orig := string(ri.Rune)
mapped := ""
if ri.CaseMode == cUpper {
mapped = ri.mapping(cLower)
} else {
mapped = ri.mapping(cUpper)
}
if len(orig) != len(mapped) {
makeException(ri)
return
}
n := len(orig)
// Create per-byte XOR mask.
var b []byte
for i := 0; i < n; i++ {
b = append(b, orig[i]^mapped[i])
}
// Remove leading 0 bytes, but keep at least one byte.
for ; len(b) > 1 && b[0] == 0; b = b[1:] {
}
if len(b) == 1 && b[0]&0xc0 == 0 {
ri.entry |= info(b[0]) << xorShift
return
}
key := string(b)
x, ok := xorCache[key]
if !ok {
xorData = append(xorData, 0) // for detecting start of sequence
xorData = append(xorData, b...)
x = len(xorData) - 1
xorCache[key] = x
}
ri.entry |= info(x<<xorShift) | xorIndexBit
}
var xorCache = map[string]int{}
// xorData contains byte-wise XOR data for the least significant bytes of a
// UTF-8 encoded rune. An index points to the last byte. The sequence starts
// with a zero terminator.
var xorData = []byte{}
// See the comments in gen_trieval.go re "the exceptions slice".
var exceptionData = []byte{0}
// makeException encodes case mappings that cannot be expressed in a simple
// XOR diff.
func makeException(ri *runeInfo) {
ri.entry |= exceptionBit
if ccc := ri.entry & cccMask; ccc != cccZero {
log.Fatalf("%U:CCC type was %d; want %d", ri.Rune, ccc, cccZero)
}
if len(exceptionData) >= 1<<numExceptionBits {
log.Fatalf("%U:exceptionData too large %x > %d bits", ri.Rune, len(exceptionData), numExceptionBits)
}
// Set the offset in the exceptionData array.
ri.entry |= info(len(exceptionData) << exceptionShift)
orig := string(ri.Rune)
tc := ri.mapping(cTitle)
uc := ri.mapping(cUpper)
lc := ri.mapping(cLower)
// addString sets the length of a string and adds it to the expansions array.
addString := func(s string, b *byte) {
if len(s) == 0 {
// Zero-length mappings exist, but only for conditional casing,
// which we are representing outside of this table.
log.Fatalf("%U: has zero-length mapping.", ri.Rune)
}
*b <<= 3
if s != orig {
n := len(s)
if n > 7 {
log.Fatalf("%U: mapping larger than 7 (%d)", ri.Rune, n)
}
*b |= byte(n)
exceptionData = append(exceptionData, s...)
}
}
// byte 0:
exceptionData = append(exceptionData, 0)
// byte 1:
p := len(exceptionData)
exceptionData = append(exceptionData, 0)
ct := ri.CaseMode
if ct != cLower {
addString(lc, &exceptionData[p])
}
if ct != cUpper {
addString(uc, &exceptionData[p])
}
if ct != cTitle {
// If title is the same as upper, we set it to the original string so
// that it will be marked as not present. This implies title case is
// the same as upper case.
if tc == uc {
tc = orig
}
addString(tc, &exceptionData[p])
}
}
// sparseCompacter is a trie value block Compacter. There are many cases where
// successive runes alternate between lower- and upper-case. This Compacter
// exploits this by adding a special case type where the case value is obtained
// from or-ing it with the least-significant bit of the rune, creating large
// ranges of equal case values that compress well.
type sparseCompacter struct {
sparseBlocks [][]uint16
sparseOffsets []uint16
sparseCount int
}
// makeSparse returns the number of elements that compact block would contain
// as well as the modified values.
func makeSparse(vals []uint64) ([]uint16, int) {
// Copy the values.
values := make([]uint16, len(vals))
for i, v := range vals {
values[i] = uint16(v)
}
alt := func(i int, v uint16) uint16 {
if cm := info(v & fullCasedMask); cm == cUpper || cm == cLower {
// Convert cLower or cUpper to cXORCase value, which has the form 11x.
xor := v
xor &^= 1
xor |= uint16(i&1) ^ (v & 1)
xor |= 0x4
return xor
}
return v
}
var count int
var previous uint16
for i, v := range values {
if v != 0 {
// Try if the unmodified value is equal to the previous.
if v == previous {
continue
}
// Try if the xor-ed value is equal to the previous value.
a := alt(i, v)
if a == previous {
values[i] = a
continue
}
// This is a new value.
count++
// Use the xor-ed value if it will be identical to the next value.
if p := i + 1; p < len(values) && alt(p, values[p]) == a {
values[i] = a
v = a
}
}
previous = v
}
return values, count
}
func (s *sparseCompacter) Size(v []uint64) (int, bool) {
_, n := makeSparse(v)
// We limit using this method to having 16 entries.
if n > 16 {
return 0, false
}
return 2 + int(reflect.TypeOf(valueRange{}).Size())*n, true
}
func (s *sparseCompacter) Store(v []uint64) uint32 {
h := uint32(len(s.sparseOffsets))
values, sz := makeSparse(v)
s.sparseBlocks = append(s.sparseBlocks, values)
s.sparseOffsets = append(s.sparseOffsets, uint16(s.sparseCount))
s.sparseCount += sz
return h
}
func (s *sparseCompacter) Handler() string {
// The sparse global variable and its lookup method is defined in gen_trieval.go.
return "sparse.lookup"
}
func (s *sparseCompacter) Print(w io.Writer) (retErr error) {
p := func(format string, args ...interface{}) {
_, err := fmt.Fprintf(w, format, args...)
if retErr == nil && err != nil {
retErr = err
}
}
ls := len(s.sparseBlocks)
if ls == len(s.sparseOffsets) {
s.sparseOffsets = append(s.sparseOffsets, uint16(s.sparseCount))
}
p("// sparseOffsets: %d entries, %d bytes\n", ls+1, (ls+1)*2)
p("var sparseOffsets = %#v\n\n", s.sparseOffsets)
ns := s.sparseCount
p("// sparseValues: %d entries, %d bytes\n", ns, ns*4)
p("var sparseValues = [%d]valueRange {", ns)
for i, values := range s.sparseBlocks {
p("\n// Block %#x, offset %#x", i, s.sparseOffsets[i])
var v uint16
for i, nv := range values {
if nv != v {
if v != 0 {
p(",hi:%#02x},", 0x80+i-1)
}
if nv != 0 {
p("\n{value:%#04x,lo:%#02x", nv, 0x80+i)
}
}
v = nv
}
if v != 0 {
p(",hi:%#02x},", 0x80+len(values)-1)
}
}
p("\n}\n\n")
return
}
// verifyProperties that properties of the runes that are relied upon in the
// implementation. Each property is marked with an identifier that is referred
// to in the places where it is used.
func verifyProperties(chars []runeInfo) {
for i, c := range chars {
r := rune(i)
// Rune properties.
// A.1: modifier never changes on lowercase. [ltLower]
if c.CCC > 0 && unicode.ToLower(r) != r {
log.Fatalf("%U: non-starter changes when lowercased", r)
}
// A.2: properties of decompositions starting with I or J. [ltLower]
d := norm.NFD.PropertiesString(string(r)).Decomposition()
if len(d) > 0 {
if d[0] == 'I' || d[0] == 'J' {
// A.2.1: we expect at least an ASCII character and a modifier.
if len(d) < 3 {
log.Fatalf("%U: length of decomposition was %d; want >= 3", r, len(d))
}
// All subsequent runes are modifiers and all have the same CCC.
runes := []rune(string(d[1:]))
ccc := chars[runes[0]].CCC
for _, mr := range runes[1:] {
mc := chars[mr]
// A.2.2: all modifiers have a CCC of Above or less.
if ccc == 0 || ccc > above {
log.Fatalf("%U: CCC of successive rune (%U) was %d; want (0,230]", r, mr, ccc)
}
// A.2.3: a sequence of modifiers all have the same CCC.
if mc.CCC != ccc {
log.Fatalf("%U: CCC of follow-up modifier (%U) was %d; want %d", r, mr, mc.CCC, ccc)
}
// A.2.4: for each trailing r, r in [0x300, 0x311] <=> CCC == Above.
if (ccc == above) != (0x300 <= mr && mr <= 0x311) {
log.Fatalf("%U: modifier %U in [U+0300, U+0311] != ccc(%U) == 230", r, mr, mr)
}
if i += len(string(mr)); i >= len(d) {
break
}
}
}
}
// A.3: no U+0307 in decomposition of Soft-Dotted rune. [ltUpper]
if unicode.Is(unicode.Soft_Dotted, r) && strings.Contains(string(d), "\u0307") {
log.Fatalf("%U: decomposition of soft-dotted rune may not contain U+0307", r)
}
// A.4: only rune U+0345 may be of CCC Iota_Subscript. [elUpper]
if c.CCC == iotaSubscript && r != 0x0345 {
log.Fatalf("%U: only rune U+0345 may have CCC Iota_Subscript", r)
}
// A.5: soft-dotted runes do not have exceptions.
if c.SoftDotted && c.entry&exceptionBit != 0 {
log.Fatalf("%U: soft-dotted has exception", r)
}
// A.6: Greek decomposition. [elUpper]
if unicode.Is(unicode.Greek, r) {
if b := norm.NFD.PropertiesString(string(r)).Decomposition(); b != nil {
runes := []rune(string(b))
// A.6.1: If a Greek rune decomposes and the first rune of the
// decomposition is greater than U+00FF, the rune is always
// great and not a modifier.
if f := runes[0]; unicode.IsMark(f) || f > 0xFF && !unicode.Is(unicode.Greek, f) {
log.Fatalf("%U: expeced first rune of Greek decomposition to be letter, found %U", r, f)
}
// A.6.2: Any follow-up rune in a Greek decomposition is a
// modifier of which the first should be gobbled in
// decomposition.
for _, m := range runes[1:] {
switch m {
case 0x0313, 0x0314, 0x0301, 0x0300, 0x0306, 0x0342, 0x0308, 0x0304, 0x345:
default:
log.Fatalf("%U: modifier %U is outside of expeced Greek modifier set", r, m)
}
}
}
}
// Breaking properties.
// B.1: all runes with CCC > 0 are of break type Extend.
if c.CCC > 0 && c.BreakType != "Extend" {
log.Fatalf("%U: CCC == %d, but got break type %s; want Extend", r, c.CCC, c.BreakType)
}
// B.2: all cased runes with c.CCC == 0 are of break type ALetter.
if c.CCC == 0 && c.Cased && c.BreakType != "ALetter" {
log.Fatalf("%U: cased, but got break type %s; want ALetter", r, c.BreakType)
}
// B.3: letter category.
if c.CCC == 0 && c.BreakCat != breakBreak && !c.CaseIgnorable {
if c.BreakCat != breakLetter {
log.Fatalf("%U: check for letter break type gave %d; want %d", r, c.BreakCat, breakLetter)
}
}
}
}
func genTablesTest() {
w := &bytes.Buffer{}
fmt.Fprintln(w, "var (")
printProperties(w, "DerivedCoreProperties.txt", "Case_Ignorable", verifyIgnore)
// We discard the output as we know we have perfect functions. We run them
// just to verify the properties are correct.
n := printProperties(ioutil.Discard, "DerivedCoreProperties.txt", "Cased", verifyCased)
n += printProperties(ioutil.Discard, "DerivedCoreProperties.txt", "Lowercase", verifyLower)
n += printProperties(ioutil.Discard, "DerivedCoreProperties.txt", "Uppercase", verifyUpper)
if n > 0 {
log.Fatalf("One of the discarded properties does not have a perfect filter.")
}
// <code>; <lower> ; <title> ; <upper> ; (<condition_list> ;)?
fmt.Fprintln(w, "\tspecial = map[rune]struct{ toLower, toTitle, toUpper string }{")
parser().parse("SpecialCasing.txt", func(p *ucd.Parser) {
// Skip conditional entries.
if p.String(4) != "" {
return
}
r := p.Rune(0)
fmt.Fprintf(w, "\t\t0x%04x: {%q, %q, %q},\n",
r, string(p.Runes(1)), string(p.Runes(2)), string(p.Runes(3)))
})
fmt.Fprint(w, "\t}\n\n")
// Break property
notBreak := map[rune]bool{}
parser().parse("auxiliary/WordBreakProperty.txt", func(p *ucd.Parser) {
switch p.String(1) {
case "Extend", "Format", "MidLetter", "MidNumLet", "Single_Quote",
"ALetter", "Hebrew_Letter", "Numeric", "ExtendNumLet":
notBreak[p.Rune(0)] = true
}
})
fmt.Fprintln(w, "\tbreakProp = []struct{ lo, hi rune }{")
inBreak := false
for r := rune(0); r <= lastRuneForTesting; r++ {
if isBreak := !notBreak[r]; isBreak != inBreak {
if isBreak {
fmt.Fprintf(w, "\t\t{0x%x, ", r)
} else {
fmt.Fprintf(w, "0x%x},\n", r-1)
}
inBreak = isBreak
}
}
if inBreak {
fmt.Fprintf(w, "0x%x},\n", lastRuneForTesting)
}
fmt.Fprint(w, "\t}\n\n")
// Word break test
// Filter out all samples that do not contain cased characters.
cased := map[rune]bool{}
parser().parse("DerivedCoreProperties.txt", func(p *ucd.Parser) {
if p.String(1) == "Cased" {
cased[p.Rune(0)] = true
}
})
fmt.Fprintln(w, "\tbreakTest = []string{")
parser(ucd.KeepRanges).parse("auxiliary/WordBreakTest.txt", func(p *ucd.Parser) {
c := strings.Split(p.String(0), " ")
const sep = '|'
numCased := 0
test := ""
for ; len(c) >= 2; c = c[2:] {
if c[0] == "÷" && test != "" {
test += string(sep)
}
i, err := strconv.ParseUint(c[1], 16, 32)
r := rune(i)
if err != nil {
log.Fatalf("Invalid rune %q.", c[1])
}
if r == sep {
log.Fatalf("Separator %q not allowed in test data. Pick another one.", sep)
}
if cased[r] {
numCased++
}
test += string(r)
}
if numCased > 1 {
fmt.Fprintf(w, "\t\t%q,\n", test)
}
})
fmt.Fprintln(w, "\t}")
fmt.Fprintln(w, ")")
gen.WriteGoFile("tables_test.go", "cases", w.Bytes())
}
// These functions are just used for verification that their definition have not
// changed in the Unicode Standard.
func verifyCased(r rune) bool {
return verifyLower(r) || verifyUpper(r) || unicode.IsTitle(r)
}
func verifyLower(r rune) bool {
return unicode.IsLower(r) || unicode.Is(unicode.Other_Lowercase, r)
}
func verifyUpper(r rune) bool {
return unicode.IsUpper(r) || unicode.Is(unicode.Other_Uppercase, r)
}
// verifyIgnore is an approximation of the Case_Ignorable property using the
// core unicode package. It is used to reduce the size of the test data.
func verifyIgnore(r rune) bool {
props := []*unicode.RangeTable{
unicode.Mn,
unicode.Me,
unicode.Cf,
unicode.Lm,
unicode.Sk,
}
for _, p := range props {
if unicode.Is(p, r) {
return true
}
}
return false
}
// printProperties prints tables of rune properties from the given UCD file.
// A filter func f can be given to exclude certain values. A rune r will have
// the indicated property if it is in the generated table or if f(r).
func printProperties(w io.Writer, file, property string, f func(r rune) bool) int {
verify := map[rune]bool{}
n := 0
varNameParts := strings.Split(property, "_")
varNameParts[0] = strings.ToLower(varNameParts[0])
fmt.Fprintf(w, "\t%s = map[rune]bool{\n", strings.Join(varNameParts, ""))
parser().parse(file, func(p *ucd.Parser) {
if p.String(1) == property {
r := p.Rune(0)
verify[r] = true
if !f(r) {
n++
fmt.Fprintf(w, "\t\t0x%.4x: true,\n", r)
}
}
})
fmt.Fprint(w, "\t}\n\n")
// Verify that f is correct, that is, it represents a subset of the property.
for r := rune(0); r <= lastRuneForTesting; r++ {
if !verify[r] && f(r) {
log.Fatalf("Incorrect filter func for property %q.", property)
}
}
return n
}
func genTrieval() {
src, err := ioutil.ReadFile("gen_trieval.go")
if err != nil {
log.Fatalf("reading gen_trieval.go: %v", err)
}
const toDelete = "// +build ignore\n\npackage main\n\n"
i := bytes.Index(src, []byte(toDelete))
if i < 0 {
log.Fatalf("could not find %q in gen_trieval.go", toDelete)
}
w := &bytes.Buffer{}
w.Write(src[i+len(toDelete):])
gen.WriteGoFile("trieval.go", "cases", w.Bytes())
}
// The newCaseTrie, sparseValues and sparseOffsets definitions below are
// placeholders referred to by gen_trieval.go. The real definitions are
// generated by this program and written to tables.go.
func newCaseTrie(int) int { return 0 }
var (
sparseValues [0]valueRange
sparseOffsets [0]uint16
)
// Copyright 2014 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.
// +build ignore
package main
// This file contains definitions for interpreting the trie value of the case
// trie generated by "go run gen*.go". It is shared by both the generator
// program and the resultant package. Sharing is achieved by the generator
// copying gen_trieval.go to trieval.go and changing what's above this comment.
// info holds case information for a single rune. It is the value returned
// by a trie lookup. Most mapping information can be stored in a single 16-bit
// value. If not, for example when a rune is mapped to multiple runes, the value
// stores some basic case data and an index into an array with additional data.
//
// The per-rune values have the following format:
//
// if (exception) {
// 15..5 unsigned exception index
// 4 unused
// } else {
// 15..7 XOR pattern or index to XOR pattern for case mapping
// 6 index: interpret the XOR pattern as an index
// 5..4 CCC: zero (normal or break), above or other
// }
// 3 exception: interpret this value as an exception index
// 2..0 case mode
//
// For the non-exceptional cases, a rune must be either uncased, lowercase or
// uppercase. If the rune is cased, the XOR pattern maps either a lowercase
// rune to uppercase or an uppercase rune to lowercase (applied to the 10
// least-significant bits of the rune).
//
// See the definitions below for a more detailed description of the various
// bits.
type info uint16
const (
casedMask = 0x0003
fullCasedMask = 0x0007
ignorableMask = 0x0006
ignorableValue = 0x0004
exceptionBit = 1 << 3
exceptionShift = 5
numExceptionBits = 11
xorIndexBit = 1 << 6
xorShift = 7
// There is no mapping if all xor bits and the exception bit are zero.
hasMappingMask = 0xffc0 | exceptionBit
)
// The case mode bits encodes the case type of a rune. This includes uncased,
// title, upper and lower case and case ignorable. (For a definition of these
// terms see Chapter 3 of The Unicode Standard Core Specification.) In some rare
// cases, a rune can be both cased and case-ignorable. This is encoded by
// cIgnorableCased. A rune of this type is always lower case. Some runes are
// cased while not having a mapping.
//
// A common pattern for scripts in the Unicode standard is for upper and lower
// case runes to alternate for increasing rune values (e.g. the accented Latin
// ranges starting from U+0100 and U+1E00 among others andsome Cyrillic
// characters). We use this property by defining a cXORCase mode, where the case
// mode (always upper or lower case) is derived from the rune value. As the XOR
// pattern for case mappings is often identical for successive runes, using
// cXORCase can result in large series of identical trie values. This, in turn,
// allows us to better compress the trie blocks.
const (
cUncased info = iota // 000
cTitle // 001
cLower // 010
cUpper // 011
cIgnorableUncased // 100
cIgnorableCased // 101 // lower case if mappings exist
cXORCase // 11x // case is cLower | ((rune&1) ^ x)
maxCaseMode = cUpper
)
func (c info) isCased() bool {
return c&casedMask != 0
}
func (c info) isCaseIgnorable() bool {
return c&ignorableMask == ignorableValue
}
func (c info) isCaseIgnorableAndNonBreakStarter() bool {
return c&(fullCasedMask|cccMask) == (ignorableValue | cccZero)
}
func (c info) isNotCasedAndNotCaseIgnorable() bool {
return c&fullCasedMask == 0
}
func (c info) isCaseIgnorableAndNotCased() bool {
return c&fullCasedMask == cIgnorableUncased
}
// The case mapping implementation will need to know about various Canonical
// Combining Class (CCC) values. We encode two of these in the trie value:
// cccZero (0) and cccAbove (230). If the value is cccOther, it means that
// CCC(r) > 0, but not 230. A value of cccBreak means that CCC(r) == 0 and that
// the rune also has the break category Break (see below).
const (
cccBreak info = iota << 4
cccZero
cccAbove
cccOther
cccMask = cccBreak | cccZero | cccAbove | cccOther
)
func (c info) cccVal() info {
if c&exceptionBit != 0 {
return cccZero
}
return c & cccMask
}
func (c info) cccType() info {
ccc := c.cccVal()
if ccc <= cccZero {
return cccZero
}
return ccc
}
const (
starter = 0
above = 230
iotaSubscript = 240
)
// TODO: Implement full Unicode breaking algorithm:
// 1) Implement breaking in separate package.
// 2) Use the breaker here.
// 3) Compare table size and performance of using the more generic breaker.
//
// Note that we can extend the current algorithm to be much more accurate. This
// only makes sense, though, if the performance and/or space penalty of using
// the generic breaker is big. Extra data will only be needed for non-cased
// runes, which means there are sufficient bits left in the caseType.
// Also note that the standard breaking algorithm doesn't always make sense
// for title casing. For example, a4a -> A4a, but a"4a -> A"4A (where " stands
// for modifier \u0308).
// ICU prohibits breaking in such cases as well.
// For the purpose of title casing we use an approximation of the Unicode Word
// Breaking algorithm defined in Annex #29:
// http://www.unicode.org/reports/tr29/#Default_Grapheme_Cluster_Table.
//
// For our approximation, we group the Word Break types into the following
// categories, with associated rules:
//
// 1) Letter:
// ALetter, Hebrew_Letter, Numeric, ExtendNumLet, Extend.
// Rule: Never break between consecutive runes of this category.
//
// 2) Mid:
// Format, MidLetter, MidNumLet, Single_Quote.
// (Cf. case-ignorable: MidLetter, MidNumLet or cat is Mn, Me, Cf, Lm or Sk).
// Rule: Don't break between Letter and Mid, but break between two Mids.
//
// 3) Break:
// Any other category, including NewLine, CR, LF and Double_Quote. These
// categories should always result in a break between two cased letters.
// Rule: Always break.
//
// Note 1: the Katakana and MidNum categories can, in esoteric cases, result in
// preventing a break between two cased letters. For now we will ignore this
// (e.g. [ALetter] [ExtendNumLet] [Katakana] [ExtendNumLet] [ALetter] and
// [ALetter] [Numeric] [MidNum] [Numeric] [ALetter].)
//
// Note 2: the rule for Mid is very approximate, but works in most cases. To
// improve, we could store the categories in the trie value and use a FA to
// manage breaks. See TODO comment above.
//
// Note 3: according to the spec, it is possible for the Extend category to
// introduce breaks between other categories grouped in Letter. However, this
// is undesirable for our purposes. ICU prevents breaks in such cases as well.
// isBreak returns whether this rune should introduce a break.
func (c info) isBreak() bool {
return c.cccVal() == cccBreak
}
// isLetter returns whether the rune is of break type ALetter, Hebrew_Letter,
// Numeric, ExtendNumLet, or Extend.
func (c info) isLetter() bool {
ccc := c.cccVal()
if ccc == cccZero {
return !c.isCaseIgnorable()
}
return ccc != cccBreak
}
// The exceptions slice holds data that does not fit in a normal info entry.
// The entry is pointed to by the exception index in an entry. It has the
// following format:
//
// Header:
// byte 0: // TODO: case folding not implemented yet.
// 7 conditional case folding
// 6 conditional special casing
// 6..3 length of case folding
// 2..0 length of closure mapping (up to 7).
//
// byte 1:
// 7..6 unused
// 5..3 length of 1st mapping of case type
// 2..0 length of 2nd mapping of case type
//
// case 1st 2nd
// lower -> upper, title
// upper -> lower, title
// title -> lower, upper
//
// Lengths with the value 0x7 indicate no value and implies no change.
// A length of 0 indicates a mapping to zero-length string.
//
// Body bytes:
// lowercase mapping bytes
// uppercase mapping bytes
// titlecase mapping bytes
// case folding bytes
// closure mapping bytes
//
// Fallbacks:
// missing fold -> lower
// missing title -> upper
// all missing -> original rune
//
// exceptions starts with a dummy byte to enforce that there is no zero index
// value.
const (
lengthMask = 0x07
lengthBits = 3
noChange = 0
)
// References to generated trie.
var trie = newCaseTrie(0)
var sparse = sparseBlocks{
values: sparseValues[:],
offsets: sparseOffsets[:],
}
// Sparse block lookup code.
// valueRange is an entry in a sparse block.
type valueRange struct {
value uint16
lo, hi byte
}
type sparseBlocks struct {
values []valueRange
offsets []uint16
}
// lookup returns the value from values block n for byte b using binary search.
func (s *sparseBlocks) lookup(n uint32, b byte) uint16 {
lo := s.offsets[n]
hi := s.offsets[n+1]
for lo < hi {
m := lo + (hi-lo)/2
r := s.values[m]
if r.lo <= b && b <= r.hi {
return r.value
}
if b < r.lo {
hi = m
} else {
lo = m + 1
}
}
return 0
}
// lastRuneForTesting is the last rune used for testing. Everything after this
// is boring.
const lastRuneForTesting = rune(0x1FFFF)
// Copyright 2014 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 cases
// This file contains the definitions of case mappings for all supported
// languages. The rules for the language-specific tailorings were taken and
// modified from the CLDR transform definitions in common/transforms.
import (
"strings"
"unicode"
"unicode/utf8"
"gx/QmVgdgtv5rUcWWcHvHN1vdGkXi8UNztJ7JuT72YUJgG2ic/go-text/language"
"gx/QmVgdgtv5rUcWWcHvHN1vdGkXi8UNztJ7JuT72YUJgG2ic/go-text/transform"
"gx/QmVgdgtv5rUcWWcHvHN1vdGkXi8UNztJ7JuT72YUJgG2ic/go-text/unicode/norm"
)
// A mapFunc takes a context set to the current rune and writes the mapped
// version to the same context. It may advance the context to the next rune. It
// returns whether a checkpoint is possible: whether the pDst bytes written to
// dst so far won't need changing as we see more source bytes.
type mapFunc func(*context) bool
// maxIgnorable defines the maximum number of ignorables to consider for
// lookahead operations.
const maxIgnorable = 30
// supported lists the language tags for which we have tailorings.
const supported = "und af az el lt nl tr"
func init() {
tags := []language.Tag{}
for _, s := range strings.Split(supported, " ") {
tags = append(tags, language.MustParse(s))
}
matcher = language.NewMatcher(tags)
Supported = language.NewCoverage(tags)
}
var (
matcher language.Matcher
Supported language.Coverage
// We keep the following lists separate, instead of having a single per-
// language struct, to give the compiler a chance to remove unused code.
// Some uppercase mappers are stateless, so we can precompute the
// Transformers and save a bit on runtime allocations.
upperFunc = []mapFunc{
nil, // und
nil, // af
aztrUpper(upper), // az
elUpper, // el
ltUpper(upper), // lt
nil, // nl
aztrUpper(upper), // tr
}
undUpper transform.Transformer = &undUpperCaser{}
lowerFunc = []mapFunc{
lower, // und
lower, // af
aztrLower, // az
lower, // el
ltLower, // lt
lower, // nl
aztrLower, // tr
}
titleInfos = []struct {
title, lower mapFunc
rewrite func(*context)
}{
{title, lower, nil}, // und
{title, lower, afnlRewrite}, // af
{aztrUpper(title), aztrLower, nil}, // az
{title, lower, nil}, // el
{ltUpper(title), ltLower, nil}, // lt
{nlTitle, lower, afnlRewrite}, // nl
{aztrUpper(title), aztrLower, nil}, // tr
}
)
func makeUpper(t language.Tag, o options) transform.Transformer {
_, i, _ := matcher.Match(t)
f := upperFunc[i]
if f == nil {
return undUpper
}
return &simpleCaser{f: f}
}
func makeLower(t language.Tag, o options) transform.Transformer {
_, i, _ := matcher.Match(t)
f := lowerFunc[i]
if o.noFinalSigma {
return &simpleCaser{f: f}
}
return &lowerCaser{
first: f,
midWord: finalSigma(f),
}
}
func makeTitle(t language.Tag, o options) transform.Transformer {
_, i, _ := matcher.Match(t)
x := &titleInfos[i]
lower := x.lower
if o.noLower {
lower = (*context).copy
} else if !o.noFinalSigma {
lower = finalSigma(lower)
}
return &titleCaser{
title: x.title,
lower: lower,
rewrite: x.rewrite,
}
}
// TODO: consider a similar special case for the fast majority lower case. This
// is a bit more involved so will require some more precise benchmarking to
// justify it.
type undUpperCaser struct{ transform.NopResetter }
// undUpperCaser implements the Transformer interface for doing an upper case
// mapping for the root locale (und). It eliminates the need for an allocation
// as it prevents escaping by not using function pointers.
func (t *undUpperCaser) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
c := context{dst: dst, src: src, atEOF: atEOF}
for c.next() {
upper(&c)
c.checkpoint()
}
return c.ret()
}
type simpleCaser struct {
context
f mapFunc
}
// simpleCaser implements the Transformer interface for doing a case operation
// on a rune-by-rune basis.
func (t *simpleCaser) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
t.context = context{dst: dst, src: src, atEOF: atEOF}
c := &t.context
for c.next() && t.f(c) {
c.checkpoint()
}
return c.ret()
}
// lowerCaser implements the Transformer interface. The default Unicode lower
// casing requires different treatment for the first and subsequent characters
// of a word, most notably to handle the Greek final Sigma.
type lowerCaser struct {
context
first, midWord mapFunc
}
func (t *lowerCaser) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
t.context = context{dst: dst, src: src, atEOF: atEOF}
c := &t.context
for isInterWord := true; c.next(); {
if isInterWord {
if c.info.isCased() {
if !t.first(c) {
break
}
isInterWord = false
} else if !c.copy() {
break
}
} else {
if c.info.isNotCasedAndNotCaseIgnorable() {
if !c.copy() {
break
}
isInterWord = true
} else if !t.midWord(c) {
break
}
}
c.checkpoint()
}
return c.ret()
}
// titleCaser implements the Transformer interface. Title casing algorithms
// distinguish between the first letter of a word and subsequent letters of the
// same word. It uses state to avoid requiring a potentially infinite lookahead.
type titleCaser struct {
context
// rune mappings used by the actual casing algorithms.
title, lower mapFunc
rewrite func(*context)
}
// Transform implements the standard Unicode title case algorithm as defined in
// Chapter 3 of The Unicode Standard:
// toTitlecase(X): Find the word boundaries in X according to Unicode Standard
// Annex #29, "Unicode Text Segmentation." For each word boundary, find the
// first cased character F following the word boundary. If F exists, map F to
// Titlecase_Mapping(F); then map all characters C between F and the following
// word boundary to Lowercase_Mapping(C).
func (t *titleCaser) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
t.context = context{dst: dst, src: src, atEOF: atEOF, isMidWord: t.isMidWord}
c := &t.context
if !c.next() {
return c.ret()
}
for {
p := c.info
if t.rewrite != nil {
t.rewrite(c)
}
wasMid := p.isCaseIgnorableAndNonBreakStarter()
// Break out of this loop on failure to ensure we do not modify the
// state incorrectly.
if p.isCased() && !p.isCaseIgnorableAndNotCased() {
if !c.isMidWord {
if !t.title(c) {
break
}
c.isMidWord = true
} else if !t.lower(c) {
break
}
} else if !c.copy() {
break
}
// TODO: make this an "else if" if we can prove that no rune that does
// not match the first condition of the if statement can be a break.
if p.isBreak() {
c.isMidWord = false
}
// As we save the state of the transformer, it is safe to call
// checkpoint after any successful write.
c.checkpoint()
if !c.next() {
break
}
if wasMid && c.info.isCaseIgnorableAndNonBreakStarter() {
c.isMidWord = false
}
}
return c.ret()
}
// lower writes the lowercase version of the current rune to dst.
func lower(c *context) bool {
if c.info&hasMappingMask == 0 || c.caseType() == cLower {
return c.copy()
}
if c.info&exceptionBit == 0 {
return c.copyXOR()
}
e := exceptions[c.info>>exceptionShift+1:]
if nLower := (e[0] >> lengthBits) & lengthMask; nLower != noChange {
return c.writeString(e[1 : 1+nLower])
}
return c.copy()
}
// upper writes the uppercase version of the current rune to dst.
func upper(c *context) bool {
ct := c.caseType()
if c.info&hasMappingMask == 0 || ct == cUpper {
return c.copy()
}
if c.info&exceptionBit == 0 {
return c.copyXOR()
}
e := exceptions[c.info>>exceptionShift+1:]
// Get length of first special case mapping.
n := (e[0] >> lengthBits) & lengthMask
if ct == cTitle {
// The first special case mapping is for lower. Set n to the second.
if n == noChange {
n = 0
}
n, e = e[0]&lengthMask, e[n:]
}
if n != noChange {
return c.writeString(e[1 : 1+n])
}
return c.copy()
}
// title writes the title case version of the current rune to dst.
func title(c *context) bool {
ct := c.caseType()
if c.info&hasMappingMask == 0 || ct == cTitle {
return c.copy()
}
if c.info&exceptionBit == 0 {
if ct == cLower {
return c.copyXOR()
}
return c.copy()
}
// Get the exception data.
e := exceptions[c.info>>exceptionShift+1:]
nFirst := (e[0] >> lengthBits) & lengthMask
if nTitle := e[0] & lengthMask; nTitle != noChange {
if nFirst != noChange {
e = e[nFirst:]
}
return c.writeString(e[1 : 1+nTitle])
}
if ct == cLower && nFirst != noChange {
// Use the uppercase version instead.
return c.writeString(e[1 : 1+nFirst])
}
// Already in correct case.
return c.copy()
}
// finalSigma adds Greek final Sigma handing to another casing function. It
// determines whether a lowercased sigma should be σ or ς, by looking ahead for
// case-ignorables and a cased letters.
func finalSigma(f mapFunc) mapFunc {
return func(c *context) bool {
// ::NFD();
// # 03A3; 03C2; 03A3; 03A3; Final_Sigma; # GREEK CAPITAL LETTER SIGMA
// Σ } [:case-ignorable:]* [:cased:] → σ;
// [:cased:] [:case-ignorable:]* { Σ → ς;
// ::Any-Lower;
// ::NFC();
if !c.hasPrefix("Σ") {
return f(c)
}
p := c.pDst
c.writeString("ς")
// We need to do one more iteration after maxIgnorable, as a cased
// letter is not an ignorable and may modify the result.
for i := 0; i < maxIgnorable+1; i++ {
if !c.next() {
return false
}
if !c.info.isCaseIgnorable() {
if c.info.isCased() {
// p+1 is guaranteed to be in bounds: if writing ς was
// successful, p+1 will contain the second byte of ς. If not,
// this function will have returned after c.next returned false.
c.dst[p+1]++ // ς → σ
}
c.unreadRune()
return true
}
// A case ignorable may also introduce a word break, so we may need
// to continue searching even after detecting a break.
c.isMidWord = c.isMidWord && !c.info.isBreak()
c.copy()
}
return true
}
}
// elUpper implements Greek upper casing, which entails removing a predefined
// set of non-blocked modifiers. Note that these accents should not be removed
// for title casing!
// Example: "Οδός" -> "ΟΔΟΣ".
func elUpper(c *context) bool {
// From CLDR:
// [:Greek:] [^[:ccc=Not_Reordered:][:ccc=Above:]]*? { [\u0313\u0314\u0301\u0300\u0306\u0342\u0308\u0304] → ;
// [:Greek:] [^[:ccc=Not_Reordered:][:ccc=Iota_Subscript:]]*? { \u0345 → ;
r, _ := utf8.DecodeRune(c.src[c.pSrc:])
oldPDst := c.pDst
if !upper(c) {
return false
}
if !unicode.Is(unicode.Greek, r) {
return true
}
i := 0
// Take the properties of the uppercased rune that is already written to the
// destination. This saves us the trouble of having to uppercase the
// decomposed rune again.
if b := norm.NFD.Properties(c.dst[oldPDst:]).Decomposition(); b != nil {
// Restore the destination position and process the decomposed rune.
r, sz := utf8.DecodeRune(b)
if r <= 0xFF { // See A.6.1
return true
}
c.pDst = oldPDst
// Insert the first rune and ignore the modifiers. See A.6.2.
c.writeBytes(b[:sz])
i = len(b[sz:]) / 2 // Greek modifiers are always of length 2.
}
for ; i < maxIgnorable && c.next(); i++ {
switch r, _ := utf8.DecodeRune(c.src[c.pSrc:]); r {
// Above and Iota Subscript
case 0x0300, // U+0300 COMBINING GRAVE ACCENT
0x0301, // U+0301 COMBINING ACUTE ACCENT
0x0304, // U+0304 COMBINING MACRON
0x0306, // U+0306 COMBINING BREVE
0x0308, // U+0308 COMBINING DIAERESIS
0x0313, // U+0313 COMBINING COMMA ABOVE
0x0314, // U+0314 COMBINING REVERSED COMMA ABOVE
0x0342, // U+0342 COMBINING GREEK PERISPOMENI
0x0345: // U+0345 COMBINING GREEK YPOGEGRAMMENI
// No-op. Gobble the modifier.
default:
switch v, _ := trie.lookup(c.src[c.pSrc:]); info(v).cccType() {
case cccZero:
c.unreadRune()
return true
// We don't need to test for IotaSubscript as the only rune that
// qualifies (U+0345) was already excluded in the switch statement
// above. See A.4.
case cccAbove:
return c.copy()
default:
// Some other modifier. We're still allowed to gobble Greek
// modifiers after this.
c.copy()
}
}
}
return i == maxIgnorable
}
func ltLower(c *context) bool {
// From CLDR:
// # Introduce an explicit dot above when lowercasing capital I's and J's
// # whenever there are more accents above.
// # (of the accents used in Lithuanian: grave, acute, tilde above, and ogonek)
// # 0049; 0069 0307; 0049; 0049; lt More_Above; # LATIN CAPITAL LETTER I
// # 004A; 006A 0307; 004A; 004A; lt More_Above; # LATIN CAPITAL LETTER J
// # 012E; 012F 0307; 012E; 012E; lt More_Above; # LATIN CAPITAL LETTER I WITH OGONEK
// # 00CC; 0069 0307 0300; 00CC; 00CC; lt; # LATIN CAPITAL LETTER I WITH GRAVE
// # 00CD; 0069 0307 0301; 00CD; 00CD; lt; # LATIN CAPITAL LETTER I WITH ACUTE
// # 0128; 0069 0307 0303; 0128; 0128; lt; # LATIN CAPITAL LETTER I WITH TILDE
// ::NFD();
// I } [^[:ccc=Not_Reordered:][:ccc=Above:]]* [:ccc=Above:] → i \u0307;
// J } [^[:ccc=Not_Reordered:][:ccc=Above:]]* [:ccc=Above:] → j \u0307;
// Į } [^[:ccc=Not_Reordered:][:ccc=Above:]]* [:ccc=Above:] → į \u0307;
// Ì → i \u0307 \u0300;
// Í → i \u0307 \u0301;
// Ĩ → i \u0307 \u0303;
// ::Any-Lower();
// ::NFC();
i := 0
if r := c.src[c.pSrc]; r < utf8.RuneSelf {
lower(c)
if r != 'I' && r != 'J' {
return true
}
} else {
p := norm.NFD.Properties(c.src[c.pSrc:])
if d := p.Decomposition(); len(d) >= 3 && (d[0] == 'I' || d[0] == 'J') {
// UTF-8 optimization: the decomposition will only have an above
// modifier if the last rune of the decomposition is in [U+300-U+311].
// In all other cases, a decomposition starting with I is always
// an I followed by modifiers that are not cased themselves. See A.2.
if d[1] == 0xCC && d[2] <= 0x91 { // A.2.4.
if !c.writeBytes(d[:1]) {
return false
}
c.dst[c.pDst-1] += 'a' - 'A' // lower
// Assumption: modifier never changes on lowercase. See A.1.
// Assumption: all modifiers added have CCC = Above. See A.2.3.
return c.writeString("\u0307") && c.writeBytes(d[1:])
}
// In all other cases the additional modifiers will have a CCC
// that is less than 230 (Above). We will insert the U+0307, if
// needed, after these modifiers so that a string in FCD form
// will remain so. See A.2.2.
lower(c)
i = 1
} else {
return lower(c)
}
}
for ; i < maxIgnorable && c.next(); i++ {
switch c.info.cccType() {
case cccZero:
c.unreadRune()
return true
case cccAbove:
return c.writeString("\u0307") && c.copy() // See A.1.
default:
c.copy() // See A.1.
}
}
return i == maxIgnorable
}
func ltUpper(f mapFunc) mapFunc {
return func(c *context) bool {
// From CLDR:
// ::NFD();
// [:Soft_Dotted:] [^[:ccc=Not_Reordered:][:ccc=Above:]]* { \u0307 → ;
// ::Any-Upper();
// ::NFC();
// TODO: See A.5. A soft-dotted rune never has an exception. This would
// allow us to overload the exception bit and encode this property in
// info. Need to measure performance impact of this.
r, _ := utf8.DecodeRune(c.src[c.pSrc:])
oldPDst := c.pDst
if !f(c) {
return false
}
if !unicode.Is(unicode.Soft_Dotted, r) {
return true
}
// We don't need to do an NFD normalization, as a soft-dotted rune never
// contains U+0307. See A.3.
i := 0
for ; i < maxIgnorable && c.next(); i++ {
switch c.info.cccType() {
case cccZero:
c.unreadRune()
return true
case cccAbove:
if c.hasPrefix("\u0307") {
// We don't do a full NFC, but rather combine runes for
// some of the common cases. (Returning NFC or
// preserving normal form is neither a requirement nor
// a possibility anyway).
if !c.next() {
return false
}
if c.dst[oldPDst] == 'I' && c.pDst == oldPDst+1 && c.src[c.pSrc] == 0xcc {
s := ""
switch c.src[c.pSrc+1] {
case 0x80: // U+0300 COMBINING GRAVE ACCENT
s = "\u00cc" // U+00CC LATIN CAPITAL LETTER I WITH GRAVE
case 0x81: // U+0301 COMBINING ACUTE ACCENT
s = "\u00cd" // U+00CD LATIN CAPITAL LETTER I WITH ACUTE
case 0x83: // U+0303 COMBINING TILDE
s = "\u0128" // U+0128 LATIN CAPITAL LETTER I WITH TILDE
case 0x88: // U+0308 COMBINING DIAERESIS
s = "\u00cf" // U+00CF LATIN CAPITAL LETTER I WITH DIAERESIS
default:
}
if s != "" {
c.pDst = oldPDst
return c.writeString(s)
}
}
}
return c.copy()
default:
c.copy()
}
}
return i == maxIgnorable
}
}
func aztrUpper(f mapFunc) mapFunc {
return func(c *context) bool {
// i→İ;
if c.src[c.pSrc] == 'i' {
return c.writeString("İ")
}
return f(c)
}
}
func aztrLower(c *context) (done bool) {
// From CLDR:
// # I and i-dotless; I-dot and i are case pairs in Turkish and Azeri
// # 0130; 0069; 0130; 0130; tr; # LATIN CAPITAL LETTER I WITH DOT ABOVE
// İ→i;
// # When lowercasing, remove dot_above in the sequence I + dot_above, which will turn into i.
// # This matches the behavior of the canonically equivalent I-dot_above
// # 0307; ; 0307; 0307; tr After_I; # COMBINING DOT ABOVE
// # When lowercasing, unless an I is before a dot_above, it turns into a dotless i.
// # 0049; 0131; 0049; 0049; tr Not_Before_Dot; # LATIN CAPITAL LETTER I
// I([^[:ccc=Not_Reordered:][:ccc=Above:]]*)\u0307 → i$1 ;
// I→ı ;
// ::Any-Lower();
if c.hasPrefix("\u0130") { // İ
return c.writeString("i")
}
if c.src[c.pSrc] != 'I' {
return lower(c)
}
// We ignore the lower-case I for now, but insert it later when we know
// which form we need.
start := c.pSrc + c.sz
i := 0
Loop:
// We check for up to n ignorables before \u0307. As \u0307 is an
// ignorable as well, n is maxIgnorable-1.
for ; i < maxIgnorable && c.next(); i++ {
switch c.info.cccType() {
case cccAbove:
if c.hasPrefix("\u0307") {
return c.writeString("i") && c.writeBytes(c.src[start:c.pSrc]) // ignore U+0307
}
done = true
break Loop
case cccZero:
c.unreadRune()
done = true
break Loop
default:
// We'll write this rune after we know which starter to use.
}
}
if i == maxIgnorable {
done = true
}
return c.writeString("ı") && c.writeBytes(c.src[start:c.pSrc+c.sz]) && done
}
func nlTitle(c *context) bool {
// From CLDR:
// # Special titlecasing for Dutch initial "ij".
// ::Any-Title();
// # Fix up Ij at the beginning of a "word" (per Any-Title, notUAX #29)
// [:^WB=ALetter:] [:WB=Extend:]* [[:WB=MidLetter:][:WB=MidNumLet:]]? { Ij } → IJ ;
if c.src[c.pSrc] != 'I' && c.src[c.pSrc] != 'i' {
return title(c)
}
if !c.writeString("I") || !c.next() {
return false
}
if c.src[c.pSrc] == 'j' || c.src[c.pSrc] == 'J' {
return c.writeString("J")
}
c.unreadRune()
return true
}
// Not part of CLDR, but see http://unicode.org/cldr/trac/ticket/7078.
func afnlRewrite(c *context) {
if c.hasPrefix("'") || c.hasPrefix("’") {
c.isMidWord = true
}
}
// Copyright 2014 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 cases
import (
"bytes"
"strings"
"testing"
"gx/QmVgdgtv5rUcWWcHvHN1vdGkXi8UNztJ7JuT72YUJgG2ic/go-text/language"
"gx/QmVgdgtv5rUcWWcHvHN1vdGkXi8UNztJ7JuT72YUJgG2ic/go-text/transform"
"gx/QmVgdgtv5rUcWWcHvHN1vdGkXi8UNztJ7JuT72YUJgG2ic/go-text/unicode/norm"
)
type testCase struct {
lang string
src interface{} // string, []string, or nil to skip test
title interface{} // string, []string, or nil to skip test
lower interface{} // string, []string, or nil to skip test
upper interface{} // string, []string, or nil to skip test
opts options
}
// We don't support the NoFinalSigma option, but we use it to test the
// underlying lower casers and to be able to compare differences in performance.
func noFinalSigma(o *options) {
o.noFinalSigma = true
}
var testCases = []testCase{
0: {
lang: "und",
src: "abc aBc ABC abC İsıI ΕΣΆΣ",
title: "Abc Abc Abc Abc İsıi Εσάσ",
lower: "abc abc abc abc i\u0307sıi εσάσ",
upper: "ABC ABC ABC ABC İSII ΕΣΆΣ",
opts: getOpts(noFinalSigma),
},
1: {
lang: "und",
src: "abc aBc ABC abC İsıI ΕΣΆΣ Σ _Σ -Σ",
title: "Abc Abc Abc Abc İsıi Εσάς Σ _Σ -Σ",
lower: "abc abc abc abc i\u0307sıi εσάς σ _σ -σ",
upper: "ABC ABC ABC ABC İSII ΕΣΆΣ Σ _Σ -Σ",
},
2: { // Title cased runes.
lang: supported,
src: "DžA",
title: "Dža",
lower: "dža",
upper: "DŽA",
},
3: {
// Title breaking.
lang: supported,
src: []string{
"FOO CASE TEST",
"DON'T DO THiS",
"χωΡΊΣ χωΡΊΣ^a χωΡΊΣ:a χωΡΊΣ:^a χωΡΊΣ^ όμΩΣ Σ",
"with-hyphens",
"49ers 49ers",
`"capitalize a^a -hyphen 0X _u a_u:a`,
"MidNumLet a.b\u2018c\u2019d\u2024e\ufe52f\uff07f\uff0eg",
"MidNum a,b;c\u037ed\u0589e\u060cf\u2044g\ufe50h",
"\u0345 x\u3031x x\u05d0x \u05d0x a'.a a.a a4,a",
},
title: []string{
"Foo Case Test",
"Don't Do This",
"Χωρίς Χωρίσ^A Χωρίσ:a Χωρίσ:^A Χωρίς^ Όμως Σ",
"With-Hyphens",
// Note that 49Ers is correct according to the spec.
// TODO: provide some option to the user to treat different
// characters as cased.
"49Ers 49Ers",
`"Capitalize A^A -Hyphen 0X _U A_u:a`,
"Midnumlet A.b\u2018c\u2019d\u2024e\ufe52f\uff07f\uff0eg",
"Midnum A,B;C\u037eD\u0589E\u060cF\u2044G\ufe50H",
"\u0399 X\u3031X X\u05d0x \u05d0X A'.A A.a A4,A",
},
},
// TODO: These are known deviations from the options{} Unicode Word Breaking
// Algorithm.
// {
// "und",
// "x_\u3031_x a4,4a",
// "X_\u3031_x A4,4a", // Currently is "X_\U3031_X A4,4A".
// "x_\u3031_x a4,4a",
// "X_\u3031_X A4,4A",
// options{},
// },
4: {
// Tests title options
lang: "und",
src: "abc aBc ABC abC İsıI o'Brien",
title: "Abc ABc ABC AbC İsıI O'Brien",
opts: getOpts(NoLower),
},
5: {
lang: "el",
src: "aBc ΟΔΌΣ Οδός Σο ΣΟ Σ oΣ ΟΣ σ ἕξ \u03ac",
title: "Abc Οδός Οδός Σο Σο Σ Oς Ος Σ Ἕξ \u0386",
lower: "abc οδός οδός σο σο σ oς ος σ ἕξ \u03ac",
upper: "ABC ΟΔΟΣ ΟΔΟΣ ΣΟ ΣΟ Σ OΣ ΟΣ Σ ΕΞ \u0391", // Uppercase removes accents
},
6: {
lang: "tr az",
src: "Isiİ İsıI I\u0307sIiİ İsıI\u0307 I\u0300\u0307",
title: "Isii İsıı I\u0307sıii İsıi I\u0300\u0307",
lower: "ısii isıı isıii isıi \u0131\u0300\u0307",
upper: "ISİİ İSII I\u0307SIİİ İSII\u0307 I\u0300\u0307",
},
7: {
lang: "lt",
src: "I Ï J J̈ Į Į̈ Ì Í Ĩ xi̇̈ xj̇̈ xį̇̈ xi̇̀ xi̇́ xi̇̃ XI XÏ XJ XJ̈ XĮ XĮ̈ XI̟̤",
title: "I Ï J J̈ Į Į̈ Ì Í Ĩ Xi̇̈ Xj̇̈ Xį̇̈ Xi̇̀ Xi̇́ Xi̇̃ Xi Xi̇̈ Xj Xj̇̈ Xį Xį̇̈ Xi̟̤",
lower: "i i̇̈ j j̇̈ į į̇̈ i̇̀ i̇́ i̇̃ xi̇̈ xj̇̈ xį̇̈ xi̇̀ xi̇́ xi̇̃ xi xi̇̈ xj xj̇̈ xį xį̇̈ xi̟̤",
upper: "I Ï J J̈ Į Į̈ Ì Í Ĩ XÏ XJ̈ XĮ̈ XÌ XÍ XĨ XI XÏ XJ XJ̈ XĮ XĮ̈ XI̟̤",
},
8: {
lang: "lt",
src: "\u012e\u0300 \u00cc i\u0307\u0300 i\u0307\u0301 i\u0307\u0303 i\u0307\u0308 i\u0300\u0307",
title: "\u012e\u0300 \u00cc \u00cc \u00cd \u0128 \u00cf I\u0300\u0307",
lower: "\u012f\u0307\u0300 i\u0307\u0300 i\u0307\u0300 i\u0307\u0301 i\u0307\u0303 i\u0307\u0308 i\u0300\u0307",
upper: "\u012e\u0300 \u00cc \u00cc \u00cd \u0128 \u00cf I\u0300\u0307",
},
9: {
lang: "nl",
src: "ijs IJs Ij Ijs İJ İJs aa aA 'ns 'S",
title: "IJs IJs IJ IJs İj İjs Aa Aa 'ns 's",
},
// Note: this specification is not currently part of CLDR. The same holds
// for the leading apostrophe handling for Dutch.
// See http://unicode.org/cldr/trac/ticket/7078.
10: {
lang: "af",
src: "wag 'n bietjie",
title: "Wag 'n Bietjie",
lower: "wag 'n bietjie",
upper: "WAG 'N BIETJIE",
},
}
func TestCaseMappings(t *testing.T) {
for i, tt := range testCases {
src, ok := tt.src.([]string)
if !ok {
src = strings.Split(tt.src.(string), " ")
}
for _, lang := range strings.Split(tt.lang, " ") {
tag := language.MustParse(lang)
testEntry := func(name string, mk func(language.Tag, options) transform.Transformer, gold interface{}) {
c := Caser{mk(tag, tt.opts)}
if gold != nil {
wants, ok := gold.([]string)
if !ok {
wants = strings.Split(gold.(string), " ")
}
for j, want := range wants {
if got := c.String(src[j]); got != want {
t.Errorf("%d:%s:\n%s.String(%+q):\ngot %+q;\nwant %+q", i, lang, name, src[j], got, want)
}
}
}
dst := make([]byte, 256) // big enough to hold any result
src := []byte(strings.Join(src, " "))
v := testing.AllocsPerRun(20, func() {
c.Transform(dst, src, true)
})
if v > 1.1 {
t.Errorf("%d:%s:\n%s: number of allocs was %f; want 0", i, lang, name, v)
}
}
testEntry("Upper", makeUpper, tt.upper)
testEntry("Lower", makeLower, tt.lower)
testEntry("Title", makeTitle, tt.title)
}
}
}
// TestAlloc tests that some mapping methods should not cause any allocation.
func TestAlloc(t *testing.T) {
dst := make([]byte, 256) // big enough to hold any result
src := []byte(txtNonASCII)
for i, f := range []func() Caser{
func() Caser { return Upper(language.Und) },
func() Caser { return Lower(language.Und) },
func() Caser { return Title(language.Und) },
} {
var c Caser
v := testing.AllocsPerRun(2, func() {
c = f()
})
if v > 1 {
// TODO: Right now only Upper has 1 allocation. Special-case Lower
// and Title as well to have less allocations for the root locale.
t.Skipf("%d:init: number of allocs was %f; want 0", i, v)
}
v = testing.AllocsPerRun(2, func() {
c.Transform(dst, src, true)
})
if v > 0 {
t.Errorf("%d:transform: number of allocs was %f; want 0", i, v)
}
}
}
func TestShortBuffersAndOverflow(t *testing.T) {
// minBufSize is the size of the buffer by which the casing operation in
// this package are guaranteed to make progress.
const minBufSize = norm.MaxSegmentSize
for i, tt := range []struct {
desc, src, want string
firstErr error
dstSize, srcSize int
t transform.Transformer
}{{
desc: "und upper: short dst",
src: "abcdefg",
want: "ABCDEFG",
firstErr: transform.ErrShortDst,
dstSize: 3,
srcSize: minBufSize,
t: Upper(language.Und),
}, {
desc: "und upper: short src",
src: "123é56",
want: "123É56",
firstErr: transform.ErrShortSrc,
dstSize: 4,
srcSize: 4,
t: Upper(language.Und),
}, {
desc: "und upper: no error on short",
src: "12",
want: "12",
firstErr: nil,
dstSize: 1,
srcSize: 1,
t: Upper(language.Und),
}, {
desc: "und lower: short dst",
src: "ABCDEFG",
want: "abcdefg",
firstErr: transform.ErrShortDst,
dstSize: 3,
srcSize: minBufSize,
t: Lower(language.Und),
}, {
desc: "und lower: short src",
src: "123É56",
want: "123é56",
firstErr: transform.ErrShortSrc,
dstSize: 4,
srcSize: 4,
t: Lower(language.Und),
}, {
desc: "und lower: no error on short",
src: "12",
want: "12",
firstErr: nil,
dstSize: 1,
srcSize: 1,
t: Lower(language.Und),
}, {
desc: "final sigma: no error",
src: "ΟΣ",
want: "Ος",
dstSize: minBufSize,
srcSize: minBufSize,
t: Title(language.Und),
}, {
desc: "final sigma: short source",
src: "ΟΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣ",
want: "Οσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσς",
firstErr: transform.ErrShortSrc,
dstSize: minBufSize,
srcSize: 10,
t: Title(language.Und),
}, {
desc: "final sigma: short destination 1",
src: "ΟΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣ",
want: "Οσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσς",
firstErr: transform.ErrShortDst,
dstSize: 10,
srcSize: minBufSize,
t: Title(language.Und),
}, {
desc: "final sigma: short destination 2",
src: "ΟΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣ",
want: "Οσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσς",
firstErr: transform.ErrShortDst,
dstSize: 9,
srcSize: minBufSize,
t: Title(language.Und),
}, {
desc: "final sigma: short destination 3",
src: "ΟΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣ",
want: "Οσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσς",
firstErr: transform.ErrShortDst,
dstSize: 8,
srcSize: minBufSize,
t: Title(language.Und),
}, {
desc: "clipped UTF-8 rune",
src: "σσσσσσσσσσσ",
want: "Σσσσσσσσσσσ",
firstErr: transform.ErrShortSrc,
dstSize: minBufSize,
srcSize: 5,
t: Title(language.Und),
}, {
desc: "clipped UTF-8 rune atEOF",
src: "σσσ" + string([]byte{0xC0}),
want: "Σσσ" + string([]byte{0xC0}),
dstSize: minBufSize,
srcSize: minBufSize,
t: Title(language.Und),
}, {
// Note: the choice to change the final sigma at the end in case of
// too many case ignorables is arbitrary. The main reason for this
// choice is that it results in simpler code.
desc: "final sigma: max ignorables",
src: "ΟΣ" + strings.Repeat(".", maxIgnorable) + "a",
want: "Οσ" + strings.Repeat(".", maxIgnorable) + "a",
dstSize: minBufSize,
srcSize: minBufSize,
t: Title(language.Und),
}, {
// Note: the choice to change the final sigma at the end in case of
// too many case ignorables is arbitrary. The main reason for this
// choice is that it results in simpler code.
desc: "final sigma: too many ignorables",
src: "ΟΣ" + strings.Repeat(".", maxIgnorable+1) + "a",
want: "Ος" + strings.Repeat(".", maxIgnorable+1) + "a",
dstSize: minBufSize,
srcSize: len("ΟΣ" + strings.Repeat(".", maxIgnorable+1)),
t: Title(language.Und),
}, {
desc: "el upper: max ignorables",
src: "ο" + strings.Repeat("\u0321", maxIgnorable-1) + "\u0313",
want: "Ο" + strings.Repeat("\u0321", maxIgnorable-1),
dstSize: minBufSize,
srcSize: minBufSize,
t: Upper(language.Greek),
}, {
desc: "el upper: too many ignorables",
src: "ο" + strings.Repeat("\u0321", maxIgnorable) + "\u0313",
want: "Ο" + strings.Repeat("\u0321", maxIgnorable) + "\u0313",
dstSize: minBufSize,
srcSize: len("ο" + strings.Repeat("\u0321", maxIgnorable)),
t: Upper(language.Greek),
}, {
desc: "el upper: short dst",
src: "123ο",
want: "123Ο",
firstErr: transform.ErrShortDst,
dstSize: 3,
srcSize: minBufSize,
t: Upper(language.Greek),
}, {
desc: "lt lower: max ignorables",
src: "I" + strings.Repeat("\u0321", maxIgnorable-1) + "\u0300",
want: "i" + strings.Repeat("\u0321", maxIgnorable-1) + "\u0307\u0300",
dstSize: minBufSize,
srcSize: minBufSize,
t: Lower(language.Lithuanian),
}, {
desc: "lt lower: too many ignorables",
src: "I" + strings.Repeat("\u0321", maxIgnorable) + "\u0300",
want: "i" + strings.Repeat("\u0321", maxIgnorable) + "\u0300",
dstSize: minBufSize,
srcSize: len("I" + strings.Repeat("\u0321", maxIgnorable)),
t: Lower(language.Lithuanian),
}, {
desc: "lt lower: decomposition with short dst buffer 1",
src: "aaaaa\u00cc", // U+00CC LATIN CAPITAL LETTER I GRAVE
firstErr: transform.ErrShortDst,
want: "aaaaai\u0307\u0300",
dstSize: 5,
srcSize: minBufSize,
t: Lower(language.Lithuanian),
}, {
desc: "lt lower: decomposition with short dst buffer 2",
src: "aaaa\u00cc", // U+00CC LATIN CAPITAL LETTER I GRAVE
firstErr: transform.ErrShortDst,
want: "aaaai\u0307\u0300",
dstSize: 5,
srcSize: minBufSize,
t: Lower(language.Lithuanian),
}, {
desc: "lt upper: max ignorables",
src: "i" + strings.Repeat("\u0321", maxIgnorable-1) + "\u0307\u0300",
want: "I" + strings.Repeat("\u0321", maxIgnorable-1) + "\u0300",
dstSize: minBufSize,
srcSize: minBufSize,
t: Upper(language.Lithuanian),
}, {
desc: "lt upper: too many ignorables",
src: "i" + strings.Repeat("\u0321", maxIgnorable) + "\u0307\u0300",
want: "I" + strings.Repeat("\u0321", maxIgnorable) + "\u0307\u0300",
dstSize: minBufSize,
srcSize: len("i" + strings.Repeat("\u0321", maxIgnorable)),
t: Upper(language.Lithuanian),
}, {
desc: "lt upper: short dst",
src: "12i\u0307\u0300",
want: "12\u00cc",
firstErr: transform.ErrShortDst,
dstSize: 3,
srcSize: minBufSize,
t: Upper(language.Lithuanian),
}, {
desc: "aztr lower: max ignorables",
src: "I" + strings.Repeat("\u0321", maxIgnorable-1) + "\u0307\u0300",
want: "i" + strings.Repeat("\u0321", maxIgnorable-1) + "\u0300",
dstSize: minBufSize,
srcSize: minBufSize,
t: Lower(language.Turkish),
}, {
desc: "aztr lower: too many ignorables",
src: "I" + strings.Repeat("\u0321", maxIgnorable) + "\u0307\u0300",
want: "\u0131" + strings.Repeat("\u0321", maxIgnorable) + "\u0307\u0300",
dstSize: minBufSize,
srcSize: len("I" + strings.Repeat("\u0321", maxIgnorable)),
t: Lower(language.Turkish),
}, {
desc: "nl title: pre-IJ cutoff",
src: " ij",
want: " IJ",
firstErr: transform.ErrShortDst,
dstSize: 2,
srcSize: minBufSize,
t: Title(language.Dutch),
}, {
desc: "nl title: mid-IJ cutoff",
src: " ij",
want: " IJ",
firstErr: transform.ErrShortDst,
dstSize: 3,
srcSize: minBufSize,
t: Title(language.Dutch),
}} {
buf := make([]byte, tt.dstSize)
got := []byte{}
var nSrc, nDst int
var err error
for p := 0; p < len(tt.src); p += nSrc {
q := p + tt.srcSize
if q > len(tt.src) {
q = len(tt.src)
}
nDst, nSrc, err = tt.t.Transform(buf, []byte(tt.src[p:q]), q == len(tt.src))
got = append(got, buf[:nDst]...)
if p == 0 && err != tt.firstErr {
t.Errorf("%d:%s:\n error was %v; want %v", i, tt.desc, err, tt.firstErr)
break
}
}
if string(got) != tt.want {
t.Errorf("%d:%s:\ngot %+q;\nwant %+q", i, tt.desc, got, tt.want)
}
}
}
var txtASCII = strings.Repeat("The quick brown fox jumps over the lazy dog. ", 50)
// Taken from http://creativecommons.org/licenses/by-sa/3.0/vn/
const txt_vn = `Với các điều kiện sau: Ghi nhận công của tác giả. Nếu bạn sử
dụng, chuyển đổi, hoặc xây dựng dự án từ nội dung được chia sẻ này, bạn phải áp
dụng giấy phép này hoặc một giấy phép khác có các điều khoản tương tự như giấy
phép này cho dự án của bạn. Hiểu rằng: Miễn — Bất kỳ các điều kiện nào trên đây
cũng có thể được miễn bỏ nếu bạn được sự cho phép của người sở hữu bản quyền.
Phạm vi công chúng — Khi tác phẩm hoặc bất kỳ chương nào của tác phẩm đã trong
vùng dành cho công chúng theo quy định của pháp luật thì tình trạng của nó không
bị ảnh hưởng bởi giấy phép trong bất kỳ trường hợp nào.`
// http://creativecommons.org/licenses/by-sa/2.5/cn/
const txt_cn = `您可以自由: 复制、发行、展览、表演、放映、
广播或通过信息网络传播本作品 创作演绎作品
对本作品进行商业性使用 惟须遵守下列条件:
署名 — 您必须按照作者或者许可人指定的方式对作品进行署名。
相同方式共享 — 如果您改变、转换本作品或者以本作品为基础进行创作,
您只能采用与本协议相同的许可协议发布基于本作品的演绎作品。`
// Taken from http://creativecommons.org/licenses/by-sa/1.0/deed.ru
const txt_ru = `При обязательном соблюдении следующих условий: Attribution — Вы
должны атрибутировать произведение (указывать автора и источник) в порядке,
предусмотренном автором или лицензиаром (но только так, чтобы никоим образом не
подразумевалось, что они поддерживают вас или использование вами данного
произведения). Υπό τις ακόλουθες προϋποθέσεις:`
// Taken from http://creativecommons.org/licenses/by-sa/3.0/gr/
const txt_gr = `Αναφορά Δημιουργού — Θα πρέπει να κάνετε την αναφορά στο έργο με
τον τρόπο που έχει οριστεί από το δημιουργό ή το χορηγούντο την άδεια (χωρίς
όμως να εννοείται με οποιονδήποτε τρόπο ότι εγκρίνουν εσάς ή τη χρήση του έργου
από εσάς). Παρόμοια Διανομή — Εάν αλλοιώσετε, τροποποιήσετε ή δημιουργήσετε
περαιτέρω βασισμένοι στο έργο θα μπορείτε να διανέμετε το έργο που θα προκύψει
μόνο με την ίδια ή παρόμοια άδεια.`
const txtNonASCII = txt_vn + txt_cn + txt_ru + txt_gr
// TODO: Improve ASCII performance.
func benchFunc(b *testing.B, f func(b []byte) []byte, s string) {
src := []byte(s)
b.SetBytes(int64(len(src)))
for i := 0; i < b.N; i++ {
f(src)
}
}
func benchTransformer(b *testing.B, t transform.Transformer, s string) {
src := []byte(s)
dst := make([]byte, len(src))
b.SetBytes(int64(len(src)))
for i := 0; i < b.N; i++ {
t.Reset()
t.Transform(dst, src, true)
}
}
var (
noSigma = options{noFinalSigma: true}
)
func BenchmarkBytesToLower(b *testing.B) {
benchFunc(b, bytes.ToLower, txtNonASCII)
}
func BenchmarkSigmaLower(b *testing.B) {
benchTransformer(b, makeLower(language.Und, options{}), txtNonASCII)
}
func BenchmarkSimpleLower(b *testing.B) {
benchTransformer(b, makeLower(language.Und, noSigma), txtNonASCII)
}
func BenchmarkBytesToLowerASCII(b *testing.B) {
benchFunc(b, bytes.ToLower, txtASCII)
}
func BenchmarkSigmaLowerASCII(b *testing.B) {
benchTransformer(b, makeLower(language.Und, options{}), txtASCII)
}
func BenchmarkSimpleLowerASCII(b *testing.B) {
benchTransformer(b, makeLower(language.Und, noSigma), txtASCII)
}
func BenchmarkBytesToTitle(b *testing.B) {
benchFunc(b, bytes.ToTitle, txtNonASCII)
}
func BenchmarkSigmaTitle(b *testing.B) {
benchTransformer(b, makeTitle(language.Und, options{}), txtNonASCII)
}
func BenchmarkSimpleTitle(b *testing.B) {
benchTransformer(b, makeTitle(language.Und, noSigma), txtNonASCII)
}
func BenchmarkBytesToTitleASCII(b *testing.B) {
benchFunc(b, bytes.ToTitle, txtASCII)
}
func BenchmarkSigmaTitleASCII(b *testing.B) {
benchTransformer(b, makeTitle(language.Und, options{}), txtASCII)
}
func BenchmarkSimpleTitleASCII(b *testing.B) {
benchTransformer(b, makeTitle(language.Und, noSigma), txtASCII)
}
func BenchmarkBytesUpper(b *testing.B) {
benchFunc(b, bytes.ToUpper, txtNonASCII)
}
func BenchmarkUpper(b *testing.B) {
benchTransformer(b, Upper(language.Und), txtNonASCII)
}
func BenchmarkBytesUpperASCII(b *testing.B) {
benchFunc(b, bytes.ToUpper, txtASCII)
}
func BenchmarkUpperASCII(b *testing.B) {
benchTransformer(b, Upper(language.Und), txtASCII)
}
func BenchmarkUpperSmall(b *testing.B) {
benchTransformer(b, Upper(language.Und), "При")
}
func BenchmarkLowerSmall(b *testing.B) {
benchTransformer(b, Lower(language.Und), "При")
}
func BenchmarkTitleSmall(b *testing.B) {
benchTransformer(b, Title(language.Und), "при")
}
// This file was generated by go generate; DO NOT EDIT
package cases
// lookup returns the trie value for the first UTF-8 encoding in s and
// the width in bytes of this encoding. The size will be 0 if s does not
// hold enough bytes to complete the encoding. len(s) must be greater than 0.
func (t *caseTrie) lookup(s []byte) (v uint16, sz int) {
c0 := s[0]
switch {
case c0 < 0x80: // is ASCII
return caseValues[c0], 1
case c0 < 0xC0:
return 0, 1 // Illegal UTF-8: not a starter, not ASCII.
case c0 < 0xE0: // 2-byte UTF-8
if len(s) < 2 {
return 0, 0
}
i := caseIndex[c0]
c1 := s[1]
if c1 < 0x80 || 0xC0 <= c1 {
return 0, 1 // Illegal UTF-8: not a continuation byte.
}
return t.lookupValue(uint32(i), c1), 2
case c0 < 0xF0: // 3-byte UTF-8
if len(s) < 3 {
return 0, 0
}
i := caseIndex[c0]
c1 := s[1]
if c1 < 0x80 || 0xC0 <= c1 {
return 0, 1 // Illegal UTF-8: not a continuation byte.
}
o := uint32(i)<<6 + uint32(c1)
i = caseIndex[o]
c2 := s[2]
if c2 < 0x80 || 0xC0 <= c2 {
return 0, 2 // Illegal UTF-8: not a continuation byte.
}
return t.lookupValue(uint32(i), c2), 3
case c0 < 0xF8: // 4-byte UTF-8
if len(s) < 4 {
return 0, 0
}
i := caseIndex[c0]
c1 := s[1]
if c1 < 0x80 || 0xC0 <= c1 {
return 0, 1 // Illegal UTF-8: not a continuation byte.
}
o := uint32(i)<<6 + uint32(c1)
i = caseIndex[o]
c2 := s[2]
if c2 < 0x80 || 0xC0 <= c2 {
return 0, 2 // Illegal UTF-8: not a continuation byte.
}
o = uint32(i)<<6 + uint32(c2)
i = caseIndex[o]
c3 := s[3]
if c3 < 0x80 || 0xC0 <= c3 {
return 0, 3 // Illegal UTF-8: not a continuation byte.
}
return t.lookupValue(uint32(i), c3), 4
}
// Illegal rune
return 0, 1
}
// lookupUnsafe returns the trie value for the first UTF-8 encoding in s.
// s must start with a full and valid UTF-8 encoded rune.
func (t *caseTrie) lookupUnsafe(s []byte) uint16 {
c0 := s[0]
if c0 < 0x80 { // is ASCII
return caseValues[c0]
}
i := caseIndex[c0]
if c0 < 0xE0 { // 2-byte UTF-8
return t.lookupValue(uint32(i), s[1])
}
i = caseIndex[uint32(i)<<6+uint32(s[1])]
if c0 < 0xF0 { // 3-byte UTF-8
return t.lookupValue(uint32(i), s[2])
}
i = caseIndex[uint32(i)<<6+uint32(s[2])]
if c0 < 0xF8 { // 4-byte UTF-8
return t.lookupValue(uint32(i), s[3])
}
return 0
}
// lookupString returns the trie value for the first UTF-8 encoding in s and
// the width in bytes of this encoding. The size will be 0 if s does not
// hold enough bytes to complete the encoding. len(s) must be greater than 0.
func (t *caseTrie) lookupString(s string) (v uint16, sz int) {
c0 := s[0]
switch {
case c0 < 0x80: // is ASCII
return caseValues[c0], 1
case c0 < 0xC0:
return 0, 1 // Illegal UTF-8: not a starter, not ASCII.
case c0 < 0xE0: // 2-byte UTF-8
if len(s) < 2 {
return 0, 0
}
i := caseIndex[c0]
c1 := s[1]
if c1 < 0x80 || 0xC0 <= c1 {
return 0, 1 // Illegal UTF-8: not a continuation byte.
}
return t.lookupValue(uint32(i), c1), 2
case c0 < 0xF0: // 3-byte UTF-8
if len(s) < 3 {
return 0, 0
}
i := caseIndex[c0]
c1 := s[1]
if c1 < 0x80 || 0xC0 <= c1 {
return 0, 1 // Illegal UTF-8: not a continuation byte.
}
o := uint32(i)<<6 + uint32(c1)
i = caseIndex[o]
c2 := s[2]
if c2 < 0x80 || 0xC0 <= c2 {
return 0, 2 // Illegal UTF-8: not a continuation byte.
}
return t.lookupValue(uint32(i), c2), 3
case c0 < 0xF8: // 4-byte UTF-8
if len(s) < 4 {
return 0, 0
}
i := caseIndex[c0]
c1 := s[1]
if c1 < 0x80 || 0xC0 <= c1 {
return 0, 1 // Illegal UTF-8: not a continuation byte.
}
o := uint32(i)<<6 + uint32(c1)
i = caseIndex[o]
c2 := s[2]
if c2 < 0x80 || 0xC0 <= c2 {
return 0, 2 // Illegal UTF-8: not a continuation byte.
}
o = uint32(i)<<6 + uint32(c2)
i = caseIndex[o]
c3 := s[3]
if c3 < 0x80 || 0xC0 <= c3 {
return 0, 3 // Illegal UTF-8: not a continuation byte.
}
return t.lookupValue(uint32(i), c3), 4
}
// Illegal rune
return 0, 1
}
// lookupStringUnsafe returns the trie value for the first UTF-8 encoding in s.
// s must start with a full and valid UTF-8 encoded rune.
func (t *caseTrie) lookupStringUnsafe(s string) uint16 {
c0 := s[0]
if c0 < 0x80 { // is ASCII
return caseValues[c0]
}
i := caseIndex[c0]
if c0 < 0xE0 { // 2-byte UTF-8
return t.lookupValue(uint32(i), s[1])
}
i = caseIndex[uint32(i)<<6+uint32(s[1])]
if c0 < 0xF0 { // 3-byte UTF-8
return t.lookupValue(uint32(i), s[2])
}
i = caseIndex[uint32(i)<<6+uint32(s[2])]
if c0 < 0xF8 { // 4-byte UTF-8
return t.lookupValue(uint32(i), s[3])
}
return 0
}
// caseTrie. Total size: 11330 bytes (11.06 KiB). Checksum: f22dcf6778cb9014.
type caseTrie struct{}
func newCaseTrie(i int) *caseTrie {
return &caseTrie{}
}
// lookupValue determines the type of block n and looks up the value for b.
func (t *caseTrie) lookupValue(n uint32, b byte) uint16 {
switch {
case n < 17:
return uint16(caseValues[n<<6+uint32(b)])
default:
n -= 17
return uint16(sparse.lookup(n, b))
}
}
// caseValues: 19 blocks, 1216 entries, 2432 bytes
// The third block is the zero block.
var caseValues = [1216]uint16{
// Block 0x0, offset 0x0
0x27: 0x0014,
0x2e: 0x0014,
0x30: 0x0010, 0x31: 0x0010, 0x32: 0x0010, 0x33: 0x0010, 0x34: 0x0010, 0x35: 0x0010,
0x36: 0x0010, 0x37: 0x0010, 0x38: 0x0010, 0x39: 0x0010, 0x3a: 0x0014,
// Block 0x1, offset 0x40
0x41: 0x1013, 0x42: 0x1013, 0x43: 0x1013, 0x44: 0x1013, 0x45: 0x1013,
0x46: 0x1013, 0x47: 0x1013, 0x48: 0x1013, 0x49: 0x1013, 0x4a: 0x1013, 0x4b: 0x1013,
0x4c: 0x1013, 0x4d: 0x1013, 0x4e: 0x1013, 0x4f: 0x1013, 0x50: 0x1013, 0x51: 0x1013,
0x52: 0x1013, 0x53: 0x1013, 0x54: 0x1013, 0x55: 0x1013, 0x56: 0x1013, 0x57: 0x1013,
0x58: 0x1013, 0x59: 0x1013, 0x5a: 0x1013,
0x5e: 0x0004, 0x5f: 0x0010, 0x60: 0x0004, 0x61: 0x1012, 0x62: 0x1012, 0x63: 0x1012,
0x64: 0x1012, 0x65: 0x1012, 0x66: 0x1012, 0x67: 0x1012, 0x68: 0x1012, 0x69: 0x1012,
0x6a: 0x1012, 0x6b: 0x1012, 0x6c: 0x1012, 0x6d: 0x1012, 0x6e: 0x1012, 0x6f: 0x1012,
0x70: 0x1012, 0x71: 0x1012, 0x72: 0x1012, 0x73: 0x1012, 0x74: 0x1012, 0x75: 0x1012,
0x76: 0x1012, 0x77: 0x1012, 0x78: 0x1012, 0x79: 0x1012, 0x7a: 0x1012,
// Block 0x2, offset 0x80
// Block 0x3, offset 0xc0
0xc0: 0x05d2, 0xc1: 0x0753, 0xc2: 0x0093, 0xc3: 0x0092, 0xc4: 0x0093, 0xc5: 0x0092,
0xc6: 0x0753, 0xc7: 0x0793, 0xc8: 0x0792, 0xc9: 0x08d3, 0xca: 0x0a53, 0xcb: 0x0393,
0xcc: 0x0392, 0xcd: 0x0012, 0xce: 0x0bd3, 0xcf: 0x0d53, 0xd0: 0x0ed3, 0xd1: 0x0193,
0xd2: 0x0192, 0xd3: 0x1053, 0xd4: 0x11d3, 0xd5: 0x1352, 0xd6: 0x14d3, 0xd7: 0x14d3,
0xd8: 0x0093, 0xd9: 0x0092, 0xda: 0x1652, 0xdb: 0x0012, 0xdc: 0x1053, 0xdd: 0x17d3,
0xde: 0x1952, 0xdf: 0x1ad3, 0xe0: 0x0093, 0xe1: 0x0092, 0xe2: 0x0093, 0xe3: 0x0092,
0xe4: 0x0093, 0xe5: 0x0092, 0xe6: 0x1c53, 0xe7: 0x0793, 0xe8: 0x0792, 0xe9: 0x1dd3,
0xea: 0x0012, 0xeb: 0x0012, 0xec: 0x0093, 0xed: 0x0092, 0xee: 0x1c53, 0xef: 0x0f93,
0xf0: 0x0f92, 0xf1: 0x1f53, 0xf2: 0x20d3, 0xf3: 0x0393, 0xf4: 0x0392, 0xf5: 0x0193,
0xf6: 0x0192, 0xf7: 0x2253, 0xf8: 0x0093, 0xf9: 0x0092, 0xfa: 0x0012, 0xfb: 0x0010,
0xfc: 0x0093, 0xfd: 0x0092, 0xfe: 0x0012, 0xff: 0x23d2,
// Block 0x4, offset 0x100
0x100: 0x0010, 0x101: 0x0010, 0x102: 0x0010, 0x103: 0x0010, 0x104: 0x02fb, 0x105: 0x03b9,
0x106: 0x047a, 0x107: 0x053b, 0x108: 0x05f9, 0x109: 0x06ba, 0x10a: 0x077b, 0x10b: 0x0839,
0x10c: 0x08fa, 0x10d: 0x0193, 0x10e: 0x0192, 0x10f: 0x0f93, 0x110: 0x0f92, 0x111: 0x0193,
0x112: 0x0192, 0x113: 0x0393, 0x114: 0x0392, 0x115: 0x0193, 0x116: 0x0192, 0x117: 0x0793,
0x118: 0x0792, 0x119: 0x0193, 0x11a: 0x0192, 0x11b: 0x0393, 0x11c: 0x0392, 0x11d: 0x0bd2,
0x11e: 0x0093, 0x11f: 0x0092, 0x120: 0x0093, 0x121: 0x0092, 0x122: 0x0093, 0x123: 0x0092,
0x124: 0x0093, 0x125: 0x0092, 0x126: 0x0093, 0x127: 0x0092, 0x128: 0x0093, 0x129: 0x0092,
0x12a: 0x0093, 0x12b: 0x0092, 0x12c: 0x0093, 0x12d: 0x0092, 0x12e: 0x0093, 0x12f: 0x0092,
0x130: 0x09ba, 0x131: 0x0a5b, 0x132: 0x0b19, 0x133: 0x0bda, 0x134: 0x0093, 0x135: 0x0092,
0x136: 0x1353, 0x137: 0x23d3, 0x138: 0x0093, 0x139: 0x0092, 0x13a: 0x0093, 0x13b: 0x0092,
0x13c: 0x0093, 0x13d: 0x0092, 0x13e: 0x0093, 0x13f: 0x0092,
// Block 0x5, offset 0x140
0x140: 0x0e7a, 0x141: 0x0193, 0x142: 0x0192, 0x143: 0x05d3, 0x144: 0x2553, 0x145: 0x26d3,
0x146: 0x0093, 0x147: 0x0092, 0x148: 0x0093, 0x149: 0x0092, 0x14a: 0x0093, 0x14b: 0x0092,
0x14c: 0x0093, 0x14d: 0x0092, 0x14e: 0x0093, 0x14f: 0x0092, 0x150: 0x0f1a, 0x151: 0x0fba,
0x152: 0x105a, 0x153: 0x0752, 0x154: 0x0752, 0x155: 0x0012, 0x156: 0x08d2, 0x157: 0x0a52,
0x158: 0x0012, 0x159: 0x0d52, 0x15a: 0x0012, 0x15b: 0x0ed2, 0x15c: 0x10fa, 0x15d: 0x0012,
0x15e: 0x0012, 0x15f: 0x0012, 0x160: 0x1052, 0x161: 0x119a, 0x162: 0x0012, 0x163: 0x11d2,
0x164: 0x0012, 0x165: 0x123a, 0x166: 0x12da, 0x167: 0x0012, 0x168: 0x14d2, 0x169: 0x14d2,
0x16a: 0x0012, 0x16b: 0x137a, 0x16c: 0x141a, 0x16d: 0x0012, 0x16e: 0x0012, 0x16f: 0x1052,
0x170: 0x0012, 0x171: 0x14ba, 0x172: 0x17d2, 0x173: 0x0012, 0x174: 0x0012, 0x175: 0x1ad2,
0x176: 0x0012, 0x177: 0x0012, 0x178: 0x0012, 0x179: 0x0012, 0x17a: 0x0012, 0x17b: 0x0012,
0x17c: 0x0012, 0x17d: 0x155a, 0x17e: 0x0012, 0x17f: 0x0012,
// Block 0x6, offset 0x180
0x180: 0x1c52, 0x181: 0x0012, 0x182: 0x0012, 0x183: 0x1dd2, 0x184: 0x0012, 0x185: 0x0012,
0x186: 0x0012, 0x187: 0x15fa, 0x188: 0x1c52, 0x189: 0x2552, 0x18a: 0x1f52, 0x18b: 0x20d2,
0x18c: 0x26d2, 0x18d: 0x0012, 0x18e: 0x0012, 0x18f: 0x0012, 0x190: 0x0012, 0x191: 0x0012,
0x192: 0x2252, 0x193: 0x0012, 0x194: 0x0010, 0x195: 0x0012, 0x196: 0x0012, 0x197: 0x0012,
0x198: 0x0012, 0x199: 0x0012, 0x19a: 0x0012, 0x19b: 0x0012, 0x19c: 0x0012, 0x19d: 0x169a,
0x19e: 0x173a, 0x19f: 0x0012, 0x1a0: 0x0012, 0x1a1: 0x0012, 0x1a2: 0x0012, 0x1a3: 0x0012,
0x1a4: 0x0012, 0x1a5: 0x0012, 0x1a6: 0x0012, 0x1a7: 0x0012, 0x1a8: 0x0012, 0x1a9: 0x0012,
0x1aa: 0x0012, 0x1ab: 0x0012, 0x1ac: 0x0012, 0x1ad: 0x0012, 0x1ae: 0x0012, 0x1af: 0x0012,
0x1b0: 0x0015, 0x1b1: 0x0015, 0x1b2: 0x0015, 0x1b3: 0x0015, 0x1b4: 0x0015, 0x1b5: 0x0015,
0x1b6: 0x0015, 0x1b7: 0x0015, 0x1b8: 0x0015, 0x1b9: 0x0014, 0x1ba: 0x0014, 0x1bb: 0x0014,
0x1bc: 0x0014, 0x1bd: 0x0014, 0x1be: 0x0014, 0x1bf: 0x0014,
// Block 0x7, offset 0x1c0
0x1c0: 0x0024, 0x1c1: 0x0024, 0x1c2: 0x0024, 0x1c3: 0x0024, 0x1c4: 0x0024, 0x1c5: 0x2875,
0x1c6: 0x0024, 0x1c7: 0x0034, 0x1c8: 0x0034, 0x1c9: 0x0034, 0x1ca: 0x0024, 0x1cb: 0x0024,
0x1cc: 0x0024, 0x1cd: 0x0034, 0x1ce: 0x0034, 0x1cf: 0x0014, 0x1d0: 0x0024, 0x1d1: 0x0024,
0x1d2: 0x0024, 0x1d3: 0x0034, 0x1d4: 0x0034, 0x1d5: 0x0034, 0x1d6: 0x0034, 0x1d7: 0x0024,
0x1d8: 0x0034, 0x1d9: 0x0034, 0x1da: 0x0034, 0x1db: 0x0024, 0x1dc: 0x0034, 0x1dd: 0x0034,
0x1de: 0x0034, 0x1df: 0x0034, 0x1e0: 0x0034, 0x1e1: 0x0034, 0x1e2: 0x0034, 0x1e3: 0x0024,
0x1e4: 0x0024, 0x1e5: 0x0024, 0x1e6: 0x0024, 0x1e7: 0x0024, 0x1e8: 0x0024, 0x1e9: 0x0024,
0x1ea: 0x0024, 0x1eb: 0x0024, 0x1ec: 0x0024, 0x1ed: 0x0024, 0x1ee: 0x0024, 0x1ef: 0x0024,
0x1f0: 0x0093, 0x1f1: 0x0092, 0x1f2: 0x0093, 0x1f3: 0x0092, 0x1f4: 0x0014, 0x1f5: 0x0004,
0x1f6: 0x0093, 0x1f7: 0x0092, 0x1fa: 0x0015, 0x1fb: 0x29d2,
0x1fc: 0x2b52, 0x1fd: 0x2b52, 0x1ff: 0x2cd3,
// Block 0x8, offset 0x200
0x204: 0x0004, 0x205: 0x0004,
0x206: 0x1513, 0x207: 0x0014, 0x208: 0x1293, 0x209: 0x1393, 0x20a: 0x1293,
0x20c: 0x2e53, 0x20e: 0x2fd3, 0x20f: 0x3153, 0x210: 0x17da, 0x211: 0x1013,
0x212: 0x1013, 0x213: 0x1013, 0x214: 0x1013, 0x215: 0x1013, 0x216: 0x1013, 0x217: 0x1013,
0x218: 0x1013, 0x219: 0x1013, 0x21a: 0x1013, 0x21b: 0x1013, 0x21c: 0x1013, 0x21d: 0x1013,
0x21e: 0x1013, 0x21f: 0x1013, 0x220: 0x32d3, 0x221: 0x32d3, 0x223: 0x32d3,
0x224: 0x32d3, 0x225: 0x32d3, 0x226: 0x32d3, 0x227: 0x32d3, 0x228: 0x32d3, 0x229: 0x32d3,
0x22a: 0x32d3, 0x22b: 0x32d3, 0x22c: 0x1512, 0x22d: 0x1292, 0x22e: 0x1392, 0x22f: 0x1292,
0x230: 0x18da, 0x231: 0x1012, 0x232: 0x1012, 0x233: 0x1012, 0x234: 0x1012, 0x235: 0x1012,
0x236: 0x1012, 0x237: 0x1012, 0x238: 0x1012, 0x239: 0x1012, 0x23a: 0x1012, 0x23b: 0x1012,
0x23c: 0x1012, 0x23d: 0x1012, 0x23e: 0x1012, 0x23f: 0x1012,
// Block 0x9, offset 0x240
0x240: 0x32d2, 0x241: 0x32d2, 0x242: 0x3452, 0x243: 0x32d2, 0x244: 0x32d2, 0x245: 0x32d2,
0x246: 0x32d2, 0x247: 0x32d2, 0x248: 0x32d2, 0x249: 0x32d2, 0x24a: 0x32d2, 0x24b: 0x32d2,
0x24c: 0x2e52, 0x24d: 0x2fd2, 0x24e: 0x3152, 0x24f: 0x0c13, 0x250: 0x35d2, 0x251: 0x3752,
0x252: 0x0013, 0x253: 0x0013, 0x254: 0x0013, 0x255: 0x38d2, 0x256: 0x3a52, 0x257: 0x0c12,
0x258: 0x0093, 0x259: 0x0092, 0x25a: 0x0093, 0x25b: 0x0092, 0x25c: 0x0093, 0x25d: 0x0092,
0x25e: 0x0093, 0x25f: 0x0092, 0x260: 0x0093, 0x261: 0x0092, 0x262: 0x0093, 0x263: 0x0092,
0x264: 0x0093, 0x265: 0x0092, 0x266: 0x0093, 0x267: 0x0092, 0x268: 0x0093, 0x269: 0x0092,
0x26a: 0x0093, 0x26b: 0x0092, 0x26c: 0x0093, 0x26d: 0x0092, 0x26e: 0x0093, 0x26f: 0x0092,
0x270: 0x3bd2, 0x271: 0x3d52, 0x272: 0x0592, 0x273: 0x2cd2, 0x274: 0x3ed3, 0x275: 0x32d2,
0x277: 0x0793, 0x278: 0x0792, 0x279: 0x0593, 0x27a: 0x0093, 0x27b: 0x0092,
0x27c: 0x0012, 0x27d: 0x29d3, 0x27e: 0x2b53, 0x27f: 0x2b53,
// Block 0xa, offset 0x280
0x280: 0x0412, 0x281: 0x0412, 0x282: 0x0412, 0x283: 0x0412, 0x284: 0x0412, 0x285: 0x0412,
0x288: 0x0413, 0x289: 0x0413, 0x28a: 0x0413, 0x28b: 0x0413,
0x28c: 0x0413, 0x28d: 0x0413, 0x290: 0x1eba, 0x291: 0x0412,
0x292: 0x1f7a, 0x293: 0x0412, 0x294: 0x207a, 0x295: 0x0412, 0x296: 0x217a, 0x297: 0x0412,
0x299: 0x0413, 0x29b: 0x0413, 0x29d: 0x0413,
0x29f: 0x0413, 0x2a0: 0x0412, 0x2a1: 0x0412, 0x2a2: 0x0412, 0x2a3: 0x0412,
0x2a4: 0x0412, 0x2a5: 0x0412, 0x2a6: 0x0412, 0x2a7: 0x0412, 0x2a8: 0x0413, 0x2a9: 0x0413,
0x2aa: 0x0413, 0x2ab: 0x0413, 0x2ac: 0x0413, 0x2ad: 0x0413, 0x2ae: 0x0413, 0x2af: 0x0413,
0x2b0: 0x5352, 0x2b1: 0x5352, 0x2b2: 0x54d2, 0x2b3: 0x54d2, 0x2b4: 0x5652, 0x2b5: 0x5652,
0x2b6: 0x57d2, 0x2b7: 0x57d2, 0x2b8: 0x5952, 0x2b9: 0x5952, 0x2ba: 0x5ad2, 0x2bb: 0x5ad2,
0x2bc: 0x29d2, 0x2bd: 0x29d2,
// Block 0xb, offset 0x2c0
0x2c0: 0x227a, 0x2c1: 0x23ba, 0x2c2: 0x24fa, 0x2c3: 0x263a, 0x2c4: 0x277a, 0x2c5: 0x28ba,
0x2c6: 0x29fa, 0x2c7: 0x2b3a, 0x2c8: 0x2c79, 0x2c9: 0x2db9, 0x2ca: 0x2ef9, 0x2cb: 0x3039,
0x2cc: 0x3179, 0x2cd: 0x32b9, 0x2ce: 0x33f9, 0x2cf: 0x3539, 0x2d0: 0x367a, 0x2d1: 0x37ba,
0x2d2: 0x38fa, 0x2d3: 0x3a3a, 0x2d4: 0x3b7a, 0x2d5: 0x3cba, 0x2d6: 0x3dfa, 0x2d7: 0x3f3a,
0x2d8: 0x4079, 0x2d9: 0x41b9, 0x2da: 0x42f9, 0x2db: 0x4439, 0x2dc: 0x4579, 0x2dd: 0x46b9,
0x2de: 0x47f9, 0x2df: 0x4939, 0x2e0: 0x4a7a, 0x2e1: 0x4bba, 0x2e2: 0x4cfa, 0x2e3: 0x4e3a,
0x2e4: 0x4f7a, 0x2e5: 0x50ba, 0x2e6: 0x51fa, 0x2e7: 0x533a, 0x2e8: 0x5479, 0x2e9: 0x55b9,
0x2ea: 0x56f9, 0x2eb: 0x5839, 0x2ec: 0x5979, 0x2ed: 0x5ab9, 0x2ee: 0x5bf9, 0x2ef: 0x5d39,
0x2f0: 0x0412, 0x2f1: 0x0412, 0x2f2: 0x5e7a, 0x2f3: 0x5ffa, 0x2f4: 0x611a,
0x2f6: 0x625a, 0x2f7: 0x631a, 0x2f8: 0x0413, 0x2f9: 0x0413, 0x2fa: 0x5353, 0x2fb: 0x5353,
0x2fc: 0x64d9, 0x2fd: 0x0004, 0x2fe: 0x65fa, 0x2ff: 0x0004,
// Block 0xc, offset 0x300
0x300: 0x0004, 0x301: 0x0004, 0x302: 0x667a, 0x303: 0x67fa, 0x304: 0x691a,
0x306: 0x6a5a, 0x307: 0x6b1a, 0x308: 0x54d3, 0x309: 0x54d3, 0x30a: 0x5653, 0x30b: 0x5653,
0x30c: 0x6cd9, 0x30d: 0x0004, 0x30e: 0x0004, 0x30f: 0x0004, 0x310: 0x0412, 0x311: 0x0412,
0x312: 0x6dfa, 0x313: 0x6efa, 0x316: 0x6ffa, 0x317: 0x70ba,
0x318: 0x0413, 0x319: 0x0413, 0x31a: 0x57d3, 0x31b: 0x57d3, 0x31d: 0x0004,
0x31e: 0x0004, 0x31f: 0x0004, 0x320: 0x0412, 0x321: 0x0412, 0x322: 0x71ba, 0x323: 0x72ba,
0x324: 0x73ba, 0x325: 0x0492, 0x326: 0x747a, 0x327: 0x753a, 0x328: 0x0413, 0x329: 0x0413,
0x32a: 0x5ad3, 0x32b: 0x5ad3, 0x32c: 0x0493, 0x32d: 0x0004, 0x32e: 0x0004, 0x32f: 0x0004,
0x332: 0x763a, 0x333: 0x77ba, 0x334: 0x78da,
0x336: 0x7a1a, 0x337: 0x7ada, 0x338: 0x5953, 0x339: 0x5953, 0x33a: 0x29d3, 0x33b: 0x29d3,
0x33c: 0x7c99, 0x33d: 0x0004, 0x33e: 0x0004,
// Block 0xd, offset 0x340
0x342: 0x0013,
0x347: 0x0013, 0x34a: 0x0012, 0x34b: 0x0013,
0x34c: 0x0013, 0x34d: 0x0013, 0x34e: 0x0012, 0x34f: 0x0012, 0x350: 0x0013, 0x351: 0x0013,
0x352: 0x0013, 0x353: 0x0012, 0x355: 0x0013,
0x359: 0x0013, 0x35a: 0x0013, 0x35b: 0x0013, 0x35c: 0x0013, 0x35d: 0x0013,
0x364: 0x0013, 0x366: 0x7dbb, 0x368: 0x0013,
0x36a: 0x7e3b, 0x36b: 0x7e9b, 0x36c: 0x0013, 0x36d: 0x0013, 0x36f: 0x0012,
0x370: 0x0013, 0x371: 0x0013, 0x372: 0x5c53, 0x373: 0x0013, 0x374: 0x0012, 0x375: 0x0010,
0x376: 0x0010, 0x377: 0x0010, 0x378: 0x0010, 0x379: 0x0012,
0x37c: 0x0012, 0x37d: 0x0012, 0x37e: 0x0013, 0x37f: 0x0013,
// Block 0xe, offset 0x380
0x380: 0x0d13, 0x381: 0x0d13, 0x382: 0x0f13, 0x383: 0x0f13, 0x384: 0x0d13, 0x385: 0x0d13,
0x386: 0x1313, 0x387: 0x1313, 0x388: 0x1513, 0x389: 0x1513, 0x38a: 0x1713, 0x38b: 0x1713,
0x38c: 0x1513, 0x38d: 0x1513, 0x38e: 0x1313, 0x38f: 0x1313, 0x390: 0x5dd2, 0x391: 0x5dd2,
0x392: 0x3bd2, 0x393: 0x3bd2, 0x394: 0x5f52, 0x395: 0x5f52, 0x396: 0x3bd2, 0x397: 0x3bd2,
0x398: 0x5dd2, 0x399: 0x5dd2, 0x39a: 0x0d12, 0x39b: 0x0d12, 0x39c: 0x0f12, 0x39d: 0x0f12,
0x39e: 0x0d12, 0x39f: 0x0d12, 0x3a0: 0x1312, 0x3a1: 0x1312, 0x3a2: 0x1512, 0x3a3: 0x1512,
0x3a4: 0x1712, 0x3a5: 0x1712, 0x3a6: 0x1512, 0x3a7: 0x1512, 0x3a8: 0x1312, 0x3a9: 0x1312,
// Block 0xf, offset 0x3c0
0x3c0: 0x3d52, 0x3c1: 0x3d52, 0x3c2: 0x3d52, 0x3c3: 0x3d52, 0x3c4: 0x3d52, 0x3c5: 0x3d52,
0x3c6: 0x3d52, 0x3c7: 0x3d52, 0x3c8: 0x3d52, 0x3c9: 0x3d52, 0x3ca: 0x3d52, 0x3cb: 0x3d52,
0x3cc: 0x3d52, 0x3cd: 0x3d52, 0x3ce: 0x3d52, 0x3cf: 0x3d52, 0x3d0: 0x60d2, 0x3d1: 0x60d2,
0x3d2: 0x60d2, 0x3d3: 0x60d2, 0x3d4: 0x60d2, 0x3d5: 0x60d2, 0x3d6: 0x60d2, 0x3d7: 0x60d2,
0x3d8: 0x60d2, 0x3d9: 0x60d2, 0x3da: 0x60d2, 0x3db: 0x60d2, 0x3dc: 0x60d2, 0x3dd: 0x60d2,
0x3de: 0x60d2, 0x3e0: 0x0093, 0x3e1: 0x0092, 0x3e2: 0x7f1b, 0x3e3: 0x5053,
0x3e4: 0x7f9b, 0x3e5: 0x801a, 0x3e6: 0x809a, 0x3e7: 0x0793, 0x3e8: 0x0792, 0x3e9: 0x0193,
0x3ea: 0x0192, 0x3eb: 0x0393, 0x3ec: 0x0392, 0x3ed: 0x811b, 0x3ee: 0x819b, 0x3ef: 0x821b,
0x3f0: 0x829b, 0x3f1: 0x0012, 0x3f2: 0x0093, 0x3f3: 0x0092, 0x3f4: 0x0012, 0x3f5: 0x0193,
0x3f6: 0x0192, 0x3f7: 0x0012, 0x3f8: 0x0012, 0x3f9: 0x0012, 0x3fa: 0x0012, 0x3fb: 0x0012,
0x3fc: 0x0015, 0x3fd: 0x0015, 0x3fe: 0x831b, 0x3ff: 0x839b,
// Block 0x10, offset 0x400
0x400: 0x0093, 0x401: 0x0092, 0x402: 0x0093, 0x403: 0x0092, 0x404: 0x0093, 0x405: 0x0092,
0x406: 0x0093, 0x407: 0x0092, 0x408: 0x0014, 0x409: 0x0004, 0x40a: 0x0004, 0x40b: 0x0393,
0x40c: 0x0392, 0x40d: 0x841b, 0x40e: 0x0012, 0x40f: 0x0010, 0x410: 0x0093, 0x411: 0x0092,
0x412: 0x0093, 0x413: 0x0092, 0x414: 0x0012, 0x415: 0x0012, 0x416: 0x0093, 0x417: 0x0092,
0x418: 0x0093, 0x419: 0x0092, 0x41a: 0x0093, 0x41b: 0x0092, 0x41c: 0x0093, 0x41d: 0x0092,
0x41e: 0x0093, 0x41f: 0x0092, 0x420: 0x0093, 0x421: 0x0092, 0x422: 0x0093, 0x423: 0x0092,
0x424: 0x0093, 0x425: 0x0092, 0x426: 0x0093, 0x427: 0x0092, 0x428: 0x0093, 0x429: 0x0092,
0x42a: 0x849b, 0x42b: 0x851b, 0x42c: 0x859b, 0x42d: 0x861b,
0x430: 0x869b, 0x431: 0x871b, 0x432: 0x879b, 0x433: 0x6253, 0x434: 0x0093, 0x435: 0x0092,
0x436: 0x0093, 0x437: 0x0092,
// Block 0x11, offset 0x440
0x440: 0x881a, 0x441: 0x88da, 0x442: 0x899a, 0x443: 0x8a5a, 0x444: 0x8b5a, 0x445: 0x8c5a,
0x446: 0x8d1a,
0x453: 0x8dda, 0x454: 0x8f1a, 0x455: 0x905a, 0x456: 0x919a, 0x457: 0x92da,
0x45d: 0x0010,
0x45e: 0x0034, 0x45f: 0x0010, 0x460: 0x0010, 0x461: 0x0010, 0x462: 0x0010, 0x463: 0x0010,
0x464: 0x0010, 0x465: 0x0010, 0x466: 0x0010, 0x467: 0x0010, 0x468: 0x0010,
0x46a: 0x0010, 0x46b: 0x0010, 0x46c: 0x0010, 0x46d: 0x0010, 0x46e: 0x0010, 0x46f: 0x0010,
0x470: 0x0010, 0x471: 0x0010, 0x472: 0x0010, 0x473: 0x0010, 0x474: 0x0010, 0x475: 0x0010,
0x476: 0x0010, 0x478: 0x0010, 0x479: 0x0010, 0x47a: 0x0010, 0x47b: 0x0010,
0x47c: 0x0010, 0x47e: 0x0010,
// Block 0x12, offset 0x480
0x482: 0x0010,
0x487: 0x0010, 0x489: 0x0010, 0x48b: 0x0010,
0x48d: 0x0010, 0x48e: 0x0010, 0x48f: 0x0010, 0x491: 0x0010,
0x492: 0x0010, 0x494: 0x0010, 0x497: 0x0010,
0x499: 0x0010, 0x49b: 0x0010, 0x49d: 0x0010,
0x49f: 0x0010, 0x4a1: 0x0010, 0x4a2: 0x0010,
0x4a4: 0x0010, 0x4a7: 0x0010, 0x4a8: 0x0010, 0x4a9: 0x0010,
0x4aa: 0x0010, 0x4ac: 0x0010, 0x4ad: 0x0010, 0x4ae: 0x0010, 0x4af: 0x0010,
0x4b0: 0x0010, 0x4b1: 0x0010, 0x4b2: 0x0010, 0x4b4: 0x0010, 0x4b5: 0x0010,
0x4b6: 0x0010, 0x4b7: 0x0010, 0x4b9: 0x0010, 0x4ba: 0x0010, 0x4bb: 0x0010,
0x4bc: 0x0010, 0x4be: 0x0010,
}
// caseIndex: 25 blocks, 1600 entries, 3200 bytes
// Block 0 is the zero block.
var caseIndex = [1600]uint16{
// Block 0x0, offset 0x0
// Block 0x1, offset 0x40
// Block 0x2, offset 0x80
// Block 0x3, offset 0xc0
0xc2: 0x11, 0xc3: 0x12, 0xc4: 0x13, 0xc5: 0x14, 0xc6: 0x01, 0xc7: 0x02,
0xc8: 0x15, 0xc9: 0x03, 0xca: 0x04, 0xcb: 0x16, 0xcc: 0x17, 0xcd: 0x05, 0xce: 0x06, 0xcf: 0x07,
0xd0: 0x18, 0xd1: 0x19, 0xd2: 0x1a, 0xd3: 0x1b, 0xd4: 0x1c, 0xd5: 0x1d, 0xd6: 0x1e, 0xd7: 0x1f,
0xd8: 0x20, 0xd9: 0x21, 0xda: 0x22, 0xdb: 0x23, 0xdc: 0x24, 0xdd: 0x25, 0xde: 0x26, 0xdf: 0x27,
0xe0: 0x02, 0xe1: 0x03, 0xe2: 0x04, 0xe3: 0x05,
0xea: 0x06, 0xeb: 0x07, 0xec: 0x07, 0xed: 0x08, 0xef: 0x09,
0xf0: 0x14, 0xf3: 0x16,
// Block 0x4, offset 0x100
0x120: 0x28, 0x121: 0x29, 0x122: 0x2a, 0x123: 0x2b, 0x124: 0x2c, 0x125: 0x2d, 0x126: 0x2e, 0x127: 0x2f,
0x128: 0x30, 0x129: 0x31, 0x12a: 0x32, 0x12b: 0x33, 0x12c: 0x34, 0x12d: 0x35, 0x12e: 0x36, 0x12f: 0x37,
0x130: 0x38, 0x131: 0x39, 0x132: 0x3a, 0x133: 0x3b, 0x134: 0x3c, 0x135: 0x3d, 0x136: 0x3e, 0x137: 0x3f,
0x138: 0x40, 0x139: 0x41, 0x13a: 0x42, 0x13b: 0x43, 0x13c: 0x44, 0x13d: 0x45, 0x13e: 0x46, 0x13f: 0x47,
// Block 0x5, offset 0x140
0x140: 0x48, 0x141: 0x49, 0x142: 0x4a, 0x143: 0x4b, 0x144: 0x22, 0x145: 0x22, 0x146: 0x22, 0x147: 0x22,
0x148: 0x22, 0x149: 0x4c, 0x14a: 0x4d, 0x14b: 0x4e, 0x14c: 0x4f, 0x14d: 0x50, 0x14e: 0x51, 0x14f: 0x52,
0x150: 0x53, 0x151: 0x22, 0x152: 0x22, 0x153: 0x22, 0x154: 0x22, 0x155: 0x22, 0x156: 0x22, 0x157: 0x22,
0x158: 0x22, 0x159: 0x54, 0x15a: 0x55, 0x15b: 0x56, 0x15c: 0x57, 0x15d: 0x58, 0x15e: 0x59, 0x15f: 0x5a,
0x160: 0x5b, 0x161: 0x5c, 0x162: 0x5d, 0x163: 0x5e, 0x164: 0x5f, 0x165: 0x60, 0x167: 0x61,
0x168: 0x62, 0x169: 0x63, 0x16a: 0x64, 0x16c: 0x65, 0x16d: 0x66, 0x16e: 0x67, 0x16f: 0x68,
0x170: 0x69, 0x171: 0x6a, 0x173: 0x6b, 0x174: 0x6c, 0x175: 0x6d, 0x176: 0x6e, 0x177: 0x6f,
0x178: 0x70, 0x179: 0x70, 0x17a: 0x71, 0x17b: 0x70, 0x17c: 0x72, 0x17d: 0x08, 0x17e: 0x09, 0x17f: 0x0a,
// Block 0x6, offset 0x180
0x180: 0x73, 0x181: 0x74, 0x182: 0x75, 0x183: 0x76, 0x184: 0x0b, 0x185: 0x77, 0x186: 0x78,
0x192: 0x79, 0x193: 0x0c,
0x1b0: 0x7a, 0x1b1: 0x0d, 0x1b2: 0x70, 0x1b3: 0x7b, 0x1b4: 0x7c, 0x1b5: 0x7d, 0x1b6: 0x7e, 0x1b7: 0x7f,
0x1b8: 0x80,
// Block 0x7, offset 0x1c0
0x1c0: 0x81, 0x1c2: 0x82, 0x1c3: 0x83, 0x1c4: 0x84, 0x1c5: 0x22, 0x1c6: 0x85,
// Block 0x8, offset 0x200
0x200: 0x86, 0x201: 0x22, 0x202: 0x22, 0x203: 0x22, 0x204: 0x22, 0x205: 0x22, 0x206: 0x22, 0x207: 0x22,
0x208: 0x22, 0x209: 0x22, 0x20a: 0x22, 0x20b: 0x22, 0x20c: 0x22, 0x20d: 0x22, 0x20e: 0x22, 0x20f: 0x22,
0x210: 0x22, 0x211: 0x22, 0x212: 0x87, 0x213: 0x88, 0x214: 0x22, 0x215: 0x22, 0x216: 0x22, 0x217: 0x22,
0x218: 0x89, 0x219: 0x8a, 0x21a: 0x8b, 0x21b: 0x8c, 0x21c: 0x8d, 0x21d: 0x8e, 0x21e: 0x0e, 0x21f: 0x8f,
0x220: 0x90, 0x221: 0x91, 0x222: 0x22, 0x223: 0x92, 0x224: 0x93, 0x225: 0x94, 0x226: 0x95, 0x227: 0x96,
0x228: 0x97, 0x229: 0x98, 0x22a: 0x99, 0x22b: 0x9a, 0x22c: 0x9b, 0x22d: 0x9c, 0x22e: 0x9d, 0x22f: 0x9e,
0x230: 0x22, 0x231: 0x22, 0x232: 0x22, 0x233: 0x22, 0x234: 0x22, 0x235: 0x22, 0x236: 0x22, 0x237: 0x22,
0x238: 0x22, 0x239: 0x22, 0x23a: 0x22, 0x23b: 0x22, 0x23c: 0x22, 0x23d: 0x22, 0x23e: 0x22, 0x23f: 0x22,
// Block 0x9, offset 0x240
0x240: 0x22, 0x241: 0x22, 0x242: 0x22, 0x243: 0x22, 0x244: 0x22, 0x245: 0x22, 0x246: 0x22, 0x247: 0x22,
0x248: 0x22, 0x249: 0x22, 0x24a: 0x22, 0x24b: 0x22, 0x24c: 0x22, 0x24d: 0x22, 0x24e: 0x22, 0x24f: 0x22,
0x250: 0x22, 0x251: 0x22, 0x252: 0x22, 0x253: 0x22, 0x254: 0x22, 0x255: 0x22, 0x256: 0x22, 0x257: 0x22,
0x258: 0x22, 0x259: 0x22, 0x25a: 0x22, 0x25b: 0x22, 0x25c: 0x22, 0x25d: 0x22, 0x25e: 0x22, 0x25f: 0x22,
0x260: 0x22, 0x261: 0x22, 0x262: 0x22, 0x263: 0x22, 0x264: 0x22, 0x265: 0x22, 0x266: 0x22, 0x267: 0x22,
0x268: 0x22, 0x269: 0x22, 0x26a: 0x22, 0x26b: 0x22, 0x26c: 0x22, 0x26d: 0x22, 0x26e: 0x22, 0x26f: 0x22,
0x270: 0x22, 0x271: 0x22, 0x272: 0x22, 0x273: 0x22, 0x274: 0x22, 0x275: 0x22, 0x276: 0x22, 0x277: 0x22,
0x278: 0x22, 0x279: 0x22, 0x27a: 0x22, 0x27b: 0x22, 0x27c: 0x22, 0x27d: 0x22, 0x27e: 0x22, 0x27f: 0x22,
// Block 0xa, offset 0x280
0x280: 0x22, 0x281: 0x22, 0x282: 0x22, 0x283: 0x22, 0x284: 0x22, 0x285: 0x22, 0x286: 0x22, 0x287: 0x22,
0x288: 0x22, 0x289: 0x22, 0x28a: 0x22, 0x28b: 0x22, 0x28c: 0x22, 0x28d: 0x22, 0x28e: 0x22, 0x28f: 0x22,
0x290: 0x22, 0x291: 0x22, 0x292: 0x22, 0x293: 0x22, 0x294: 0x22, 0x295: 0x22, 0x296: 0x22, 0x297: 0x22,
0x298: 0x22, 0x299: 0x22, 0x29a: 0x22, 0x29b: 0x22, 0x29c: 0x22, 0x29d: 0x22, 0x29e: 0x9f, 0x29f: 0xa0,
// Block 0xb, offset 0x2c0
0x2ec: 0x0f, 0x2ed: 0xa1, 0x2ee: 0xa2, 0x2ef: 0xa3,
0x2f0: 0x22, 0x2f1: 0x22, 0x2f2: 0x22, 0x2f3: 0x22, 0x2f4: 0xa4, 0x2f5: 0xa5, 0x2f6: 0xa6, 0x2f7: 0xa7,
0x2f8: 0xa8, 0x2f9: 0xa9, 0x2fa: 0x22, 0x2fb: 0xaa, 0x2fc: 0xab, 0x2fd: 0xac, 0x2fe: 0xad, 0x2ff: 0xae,
// Block 0xc, offset 0x300
0x300: 0xaf, 0x301: 0xb0, 0x302: 0x22, 0x303: 0xb1, 0x305: 0xb2, 0x307: 0xb3,
0x30a: 0xb4, 0x30b: 0xb5, 0x30c: 0xb6, 0x30d: 0xb7, 0x30e: 0xb8, 0x30f: 0xb9,
0x310: 0xba, 0x311: 0xbb, 0x312: 0xbc, 0x314: 0xbd, 0x315: 0xbe,
0x318: 0x22, 0x319: 0x22, 0x31a: 0x22, 0x31b: 0x22, 0x31c: 0xbf, 0x31d: 0xc0,
0x320: 0xc1, 0x321: 0xc2, 0x322: 0xc3, 0x323: 0xc4, 0x324: 0xc5, 0x326: 0xc6,
0x328: 0xc7, 0x329: 0xc8, 0x32a: 0xc9, 0x32b: 0xca, 0x32c: 0x5e, 0x32d: 0xcb, 0x32e: 0xcc,
0x330: 0x22, 0x331: 0xcd, 0x332: 0xce, 0x333: 0xcf,
// Block 0xd, offset 0x340
0x340: 0xd0, 0x341: 0xd1, 0x342: 0xd2, 0x343: 0xd3, 0x344: 0xd4, 0x345: 0xd5, 0x346: 0xd6, 0x347: 0xd7,
0x348: 0xd8, 0x34a: 0xd9, 0x34b: 0xda, 0x34c: 0xdb, 0x34d: 0xdc,
0x352: 0xdd, 0x353: 0xde, 0x356: 0xdf, 0x357: 0xe0,
0x358: 0xe1, 0x359: 0xe2, 0x35a: 0xe3, 0x35b: 0xe4, 0x35c: 0xe5,
0x362: 0xe6, 0x363: 0xe7,
0x36b: 0xe8,
// Block 0xe, offset 0x380
0x380: 0x22, 0x381: 0x22, 0x382: 0x22, 0x383: 0x22, 0x384: 0x22, 0x385: 0x22, 0x386: 0x22, 0x387: 0x22,
0x388: 0x22, 0x389: 0x22, 0x38a: 0x22, 0x38b: 0x22, 0x38c: 0x22, 0x38d: 0x22, 0x38e: 0xe9,
0x390: 0x22, 0x391: 0xea, 0x392: 0x22, 0x393: 0x22, 0x394: 0x22, 0x395: 0xeb,
// Block 0xf, offset 0x3c0
0x3c0: 0x22, 0x3c1: 0x22, 0x3c2: 0x22, 0x3c3: 0x22, 0x3c4: 0x22, 0x3c5: 0x22, 0x3c6: 0x22, 0x3c7: 0x22,
0x3c8: 0x22, 0x3c9: 0x22, 0x3ca: 0x22, 0x3cb: 0x22, 0x3cc: 0x22, 0x3cd: 0x22, 0x3ce: 0x22, 0x3cf: 0x22,
0x3d0: 0xea,
// Block 0x10, offset 0x400
0x410: 0x22, 0x411: 0x22, 0x412: 0x22, 0x413: 0x22, 0x414: 0x22, 0x415: 0x22, 0x416: 0x22, 0x417: 0x22,
0x418: 0x22, 0x419: 0xec,
// Block 0x11, offset 0x440
0x460: 0x22, 0x461: 0x22, 0x462: 0x22, 0x463: 0x22, 0x464: 0x22, 0x465: 0x22, 0x466: 0x22, 0x467: 0x22,
0x468: 0xe8, 0x469: 0xed, 0x46b: 0xee, 0x46c: 0xef, 0x46d: 0xf0, 0x46e: 0xf1,
0x47c: 0x22, 0x47d: 0xf2, 0x47e: 0xf3,
// Block 0x12, offset 0x480
0x4b0: 0x22, 0x4b1: 0xf4, 0x4b2: 0xf5,
// Block 0x13, offset 0x4c0
0x4c5: 0xf6, 0x4c6: 0xf7,
0x4c9: 0xf8,
0x4d0: 0xf9, 0x4d1: 0xfa, 0x4d2: 0xfb, 0x4d3: 0xfc, 0x4d4: 0xfd, 0x4d5: 0xfe, 0x4d6: 0xff, 0x4d7: 0x100,
0x4d8: 0x101, 0x4d9: 0x102, 0x4da: 0x103, 0x4db: 0x104, 0x4dc: 0x105, 0x4dd: 0x106, 0x4de: 0x107, 0x4df: 0x108,
0x4e8: 0x109, 0x4e9: 0x10a, 0x4ea: 0x10b,
// Block 0x14, offset 0x500
0x520: 0x22, 0x521: 0x22, 0x522: 0x22, 0x523: 0x10c,
0x538: 0x10d, 0x539: 0x10, 0x53a: 0x10e,
// Block 0x15, offset 0x540
0x544: 0x10f, 0x545: 0x110, 0x546: 0x111,
0x54f: 0x112,
// Block 0x16, offset 0x580
0x590: 0x0a, 0x591: 0x0b, 0x592: 0x0c, 0x593: 0x0d, 0x594: 0x0e, 0x596: 0x0f,
0x59b: 0x10, 0x59d: 0x11, 0x59e: 0x12, 0x59f: 0x13,
// Block 0x17, offset 0x5c0
0x5c0: 0x113, 0x5c1: 0x114, 0x5c4: 0x114, 0x5c5: 0x114, 0x5c6: 0x114, 0x5c7: 0x115,
// Block 0x18, offset 0x600
0x620: 0x15,
}
// sparseOffsets: 262 entries, 524 bytes
var sparseOffsets = []uint16{0x0, 0x9, 0xf, 0x18, 0x24, 0x2e, 0x3a, 0x3d, 0x41, 0x44, 0x48, 0x52, 0x54, 0x59, 0x69, 0x70, 0x75, 0x83, 0x84, 0x92, 0xa1, 0xab, 0xae, 0xb4, 0xbc, 0xbe, 0xbf, 0xcb, 0xd1, 0xdf, 0xea, 0xf5, 0x100, 0x10c, 0x116, 0x121, 0x12c, 0x138, 0x144, 0x14c, 0x154, 0x15e, 0x168, 0x174, 0x17a, 0x185, 0x18a, 0x192, 0x195, 0x19a, 0x19e, 0x1a2, 0x1a9, 0x1b2, 0x1ba, 0x1bb, 0x1c4, 0x1cb, 0x1d3, 0x1d9, 0x1df, 0x1e4, 0x1e8, 0x1eb, 0x1ed, 0x1f0, 0x1f5, 0x1f6, 0x1f8, 0x1fa, 0x1fc, 0x203, 0x208, 0x20c, 0x215, 0x218, 0x21b, 0x21f, 0x220, 0x22b, 0x22c, 0x22d, 0x232, 0x23f, 0x247, 0x24f, 0x258, 0x261, 0x26a, 0x26f, 0x272, 0x27f, 0x281, 0x288, 0x28a, 0x294, 0x295, 0x2a0, 0x2a8, 0x2af, 0x2b5, 0x2b6, 0x2c4, 0x2c9, 0x2cc, 0x2d1, 0x2d5, 0x2db, 0x2e0, 0x2e3, 0x2e8, 0x2ed, 0x2ee, 0x2f4, 0x2f6, 0x2f7, 0x2f9, 0x2fb, 0x2fe, 0x2ff, 0x301, 0x304, 0x30a, 0x30e, 0x310, 0x316, 0x31d, 0x321, 0x32a, 0x32b, 0x332, 0x336, 0x33b, 0x343, 0x349, 0x34f, 0x359, 0x35e, 0x367, 0x36d, 0x374, 0x378, 0x380, 0x382, 0x384, 0x387, 0x389, 0x38b, 0x38c, 0x38d, 0x38f, 0x391, 0x397, 0x39c, 0x39e, 0x3a4, 0x3a7, 0x3a9, 0x3af, 0x3b4, 0x3b6, 0x3b7, 0x3b8, 0x3b9, 0x3bb, 0x3bd, 0x3bf, 0x3c2, 0x3c4, 0x3c7, 0x3cf, 0x3d2, 0x3d4, 0x3d6, 0x3d7, 0x3d8, 0x3da, 0x3e0, 0x3e2, 0x3e3, 0x3e5, 0x3e7, 0x3e9, 0x3f6, 0x3f7, 0x3f8, 0x3fc, 0x3fe, 0x3ff, 0x400, 0x401, 0x402, 0x406, 0x40a, 0x410, 0x412, 0x419, 0x41c, 0x420, 0x426, 0x42e, 0x434, 0x43a, 0x444, 0x44e, 0x454, 0x45a, 0x460, 0x463, 0x469, 0x46c, 0x474, 0x475, 0x47c, 0x47d, 0x480, 0x481, 0x482, 0x483, 0x484, 0x485, 0x487, 0x489, 0x48b, 0x48f, 0x490, 0x492, 0x493, 0x495, 0x49a, 0x49f, 0x4a3, 0x4a4, 0x4a7, 0x4ab, 0x4b6, 0x4ba, 0x4c2, 0x4c7, 0x4cb, 0x4ce, 0x4d2, 0x4d5, 0x4d8, 0x4dd, 0x4e1, 0x4e5, 0x4e9, 0x4ed, 0x4ef, 0x4f1, 0x4f4, 0x4f6, 0x4ff, 0x504, 0x505, 0x508, 0x509, 0x50a, 0x50c, 0x50d, 0x50e}
// sparseValues: 1294 entries, 5176 bytes
var sparseValues = [1294]valueRange{
// Block 0x0, offset 0x0
{value: 0x0004, lo: 0xa8, hi: 0xa8},
{value: 0x0012, lo: 0xaa, hi: 0xaa},
{value: 0x0014, lo: 0xad, hi: 0xad},
{value: 0x0004, lo: 0xaf, hi: 0xaf},
{value: 0x0004, lo: 0xb4, hi: 0xb4},
{value: 0x0152, lo: 0xb5, hi: 0xb5},
{value: 0x0014, lo: 0xb7, hi: 0xb7},
{value: 0x0004, lo: 0xb8, hi: 0xb8},
{value: 0x0012, lo: 0xba, hi: 0xba},
// Block 0x1, offset 0x9
{value: 0x1013, lo: 0x80, hi: 0x96},
{value: 0x1013, lo: 0x98, hi: 0x9e},
{value: 0x003a, lo: 0x9f, hi: 0x9f},
{value: 0x1012, lo: 0xa0, hi: 0xb6},
{value: 0x1012, lo: 0xb8, hi: 0xbe},
{value: 0x02d2, lo: 0xbf, hi: 0xbf},
// Block 0x2, offset 0xf
{value: 0x0097, lo: 0x80, hi: 0xaf},
{value: 0x00fb, lo: 0xb0, hi: 0xb0},
{value: 0x019a, lo: 0xb1, hi: 0xb1},
{value: 0x0097, lo: 0xb2, hi: 0xb7},
{value: 0x0012, lo: 0xb8, hi: 0xb8},
{value: 0x0196, lo: 0xb9, hi: 0xba},
{value: 0x0396, lo: 0xbb, hi: 0xbc},
{value: 0x0196, lo: 0xbd, hi: 0xbe},
{value: 0x0453, lo: 0xbf, hi: 0xbf},
// Block 0x3, offset 0x18
{value: 0x0452, lo: 0x80, hi: 0x80},
{value: 0x0196, lo: 0x81, hi: 0x82},
{value: 0x0396, lo: 0x83, hi: 0x84},
{value: 0x0196, lo: 0x85, hi: 0x86},
{value: 0x0796, lo: 0x87, hi: 0x88},
{value: 0x01fa, lo: 0x89, hi: 0x89},
{value: 0x0097, lo: 0x8a, hi: 0xb7},
{value: 0x02d3, lo: 0xb8, hi: 0xb8},
{value: 0x0196, lo: 0xb9, hi: 0xba},
{value: 0x0396, lo: 0xbb, hi: 0xbc},
{value: 0x0196, lo: 0xbd, hi: 0xbe},
{value: 0x029a, lo: 0xbf, hi: 0xbf},
// Block 0x4, offset 0x24
{value: 0x0097, lo: 0x80, hi: 0x9f},
{value: 0x1953, lo: 0xa0, hi: 0xa0},
{value: 0x0012, lo: 0xa1, hi: 0xa1},
{value: 0x0097, lo: 0xa2, hi: 0xb3},
{value: 0x0012, lo: 0xb4, hi: 0xb9},
{value: 0x0c9b, lo: 0xba, hi: 0xba},
{value: 0x0396, lo: 0xbb, hi: 0xbc},
{value: 0x1653, lo: 0xbd, hi: 0xbd},
{value: 0x0d3b, lo: 0xbe, hi: 0xbe},
{value: 0x0dda, lo: 0xbf, hi: 0xbf},
// Block 0x5, offset 0x2e
{value: 0x0015, lo: 0x80, hi: 0x81},
{value: 0x0004, lo: 0x82, hi: 0x85},
{value: 0x0014, lo: 0x86, hi: 0x91},
{value: 0x0004, lo: 0x92, hi: 0x96},
{value: 0x0014, lo: 0x97, hi: 0x97},
{value: 0x0004, lo: 0x98, hi: 0x9f},
{value: 0x0015, lo: 0xa0, hi: 0xa4},
{value: 0x0004, lo: 0xa5, hi: 0xab},
{value: 0x0014, lo: 0xac, hi: 0xac},
{value: 0x0004, lo: 0xad, hi: 0xad},
{value: 0x0014, lo: 0xae, hi: 0xae},
{value: 0x0004, lo: 0xaf, hi: 0xbf},
// Block 0x6, offset 0x3a
{value: 0x0024, lo: 0x80, hi: 0x94},
{value: 0x0034, lo: 0x95, hi: 0xbc},
{value: 0x0024, lo: 0xbd, hi: 0xbf},
// Block 0x7, offset 0x3d
{value: 0x3d53, lo: 0x80, hi: 0x8f},
{value: 0x1013, lo: 0x90, hi: 0x9f},
{value: 0x32d3, lo: 0xa0, hi: 0xaf},
{value: 0x1012, lo: 0xb0, hi: 0xbf},
// Block 0x8, offset 0x41
{value: 0x32d2, lo: 0x80, hi: 0x8f},
{value: 0x3d52, lo: 0x90, hi: 0x9f},
{value: 0x0097, lo: 0xa0, hi: 0xbf},
// Block 0x9, offset 0x44
{value: 0x0097, lo: 0x80, hi: 0x81},
{value: 0x0024, lo: 0x83, hi: 0x87},
{value: 0x0014, lo: 0x88, hi: 0x89},
{value: 0x0097, lo: 0x8a, hi: 0xbf},
// Block 0xa, offset 0x48
{value: 0x0793, lo: 0x80, hi: 0x80},
{value: 0x0196, lo: 0x81, hi: 0x82},
{value: 0x0396, lo: 0x83, hi: 0x84},
{value: 0x0196, lo: 0x85, hi: 0x86},
{value: 0x0796, lo: 0x87, hi: 0x88},
{value: 0x0196, lo: 0x89, hi: 0x8a},
{value: 0x0396, lo: 0x8b, hi: 0x8c},
{value: 0x0196, lo: 0x8d, hi: 0x8e},
{value: 0x0792, lo: 0x8f, hi: 0x8f},
{value: 0x0097, lo: 0x90, hi: 0xbf},
// Block 0xb, offset 0x52
{value: 0x0097, lo: 0x80, hi: 0xaf},
{value: 0x3d53, lo: 0xb1, hi: 0xbf},
// Block 0xc, offset 0x54
{value: 0x1813, lo: 0x80, hi: 0x8f},
{value: 0x4053, lo: 0x90, hi: 0x96},
{value: 0x0014, lo: 0x99, hi: 0x99},
{value: 0x3d52, lo: 0xa1, hi: 0xaf},
{value: 0x1812, lo: 0xb0, hi: 0xbf},
// Block 0xd, offset 0x59
{value: 0x4052, lo: 0x80, hi: 0x86},
{value: 0x19da, lo: 0x87, hi: 0x87},
{value: 0x0034, lo: 0x91, hi: 0x91},
{value: 0x0024, lo: 0x92, hi: 0x95},
{value: 0x0034, lo: 0x96, hi: 0x96},
{value: 0x0024, lo: 0x97, hi: 0x99},
{value: 0x0034, lo: 0x9a, hi: 0x9b},
{value: 0x0024, lo: 0x9c, hi: 0xa1},
{value: 0x0034, lo: 0xa2, hi: 0xa7},
{value: 0x0024, lo: 0xa8, hi: 0xa9},
{value: 0x0034, lo: 0xaa, hi: 0xaa},
{value: 0x0024, lo: 0xab, hi: 0xac},
{value: 0x0034, lo: 0xad, hi: 0xae},
{value: 0x0024, lo: 0xaf, hi: 0xaf},
{value: 0x0034, lo: 0xb0, hi: 0xbd},
{value: 0x0034, lo: 0xbf, hi: 0xbf},
// Block 0xe, offset 0x69
{value: 0x0034, lo: 0x81, hi: 0x82},
{value: 0x0024, lo: 0x84, hi: 0x84},
{value: 0x0034, lo: 0x85, hi: 0x85},
{value: 0x0034, lo: 0x87, hi: 0x87},
{value: 0x0010, lo: 0x90, hi: 0xaa},
{value: 0x0010, lo: 0xb0, hi: 0xb3},
{value: 0x0014, lo: 0xb4, hi: 0xb4},
// Block 0xf, offset 0x70
{value: 0x0014, lo: 0x80, hi: 0x85},
{value: 0x0024, lo: 0x90, hi: 0x97},
{value: 0x0034, lo: 0x98, hi: 0x9a},
{value: 0x0014, lo: 0x9c, hi: 0x9c},
{value: 0x0010, lo: 0xa0, hi: 0xbf},
// Block 0x10, offset 0x75
{value: 0x0014, lo: 0x80, hi: 0x80},
{value: 0x0010, lo: 0x81, hi: 0x8a},
{value: 0x0034, lo: 0x8b, hi: 0x92},
{value: 0x0024, lo: 0x93, hi: 0x94},
{value: 0x0034, lo: 0x95, hi: 0x96},
{value: 0x0024, lo: 0x97, hi: 0x9b},
{value: 0x0034, lo: 0x9c, hi: 0x9c},
{value: 0x0024, lo: 0x9d, hi: 0x9e},
{value: 0x0034, lo: 0x9f, hi: 0x9f},
{value: 0x0010, lo: 0xa0, hi: 0xa9},
{value: 0x0010, lo: 0xab, hi: 0xab},
{value: 0x0010, lo: 0xae, hi: 0xaf},
{value: 0x0034, lo: 0xb0, hi: 0xb0},
{value: 0x0010, lo: 0xb1, hi: 0xbf},
// Block 0x11, offset 0x83
{value: 0x0010, lo: 0x80, hi: 0xbf},
// Block 0x12, offset 0x84
{value: 0x0010, lo: 0x80, hi: 0x93},
{value: 0x0010, lo: 0x95, hi: 0x95},
{value: 0x0024, lo: 0x96, hi: 0x9c},
{value: 0x0014, lo: 0x9d, hi: 0x9d},
{value: 0x0024, lo: 0x9f, hi: 0xa2},
{value: 0x0034, lo: 0xa3, hi: 0xa3},
{value: 0x0024, lo: 0xa4, hi: 0xa4},
{value: 0x0014, lo: 0xa5, hi: 0xa6},
{value: 0x0024, lo: 0xa7, hi: 0xa8},
{value: 0x0034, lo: 0xaa, hi: 0xaa},
{value: 0x0024, lo: 0xab, hi: 0xac},
{value: 0x0034, lo: 0xad, hi: 0xad},
{value: 0x0010, lo: 0xae, hi: 0xbc},
{value: 0x0010, lo: 0xbf, hi: 0xbf},
// Block 0x13, offset 0x92
{value: 0x0014, lo: 0x8f, hi: 0x8f},
{value: 0x0010, lo: 0x90, hi: 0x90},
{value: 0x0034, lo: 0x91, hi: 0x91},
{value: 0x0010, lo: 0x92, hi: 0xaf},
{value: 0x0024, lo: 0xb0, hi: 0xb0},
{value: 0x0034, lo: 0xb1, hi: 0xb1},
{value: 0x0024, lo: 0xb2, hi: 0xb3},
{value: 0x0034, lo: 0xb4, hi: 0xb4},
{value: 0x0024, lo: 0xb5, hi: 0xb6},
{value: 0x0034, lo: 0xb7, hi: 0xb9},
{value: 0x0024, lo: 0xba, hi: 0xba},
{value: 0x0034, lo: 0xbb, hi: 0xbc},
{value: 0x0024, lo: 0xbd, hi: 0xbd},
{value: 0x0034, lo: 0xbe, hi: 0xbe},
{value: 0x0024, lo: 0xbf, hi: 0xbf},
// Block 0x14, offset 0xa1
{value: 0x0024, lo: 0x80, hi: 0x81},
{value: 0x0034, lo: 0x82, hi: 0x82},
{value: 0x0024, lo: 0x83, hi: 0x83},
{value: 0x0034, lo: 0x84, hi: 0x84},
{value: 0x0024, lo: 0x85, hi: 0x85},
{value: 0x0034, lo: 0x86, hi: 0x86},
{value: 0x0024, lo: 0x87, hi: 0x87},
{value: 0x0034, lo: 0x88, hi: 0x88},
{value: 0x0024, lo: 0x89, hi: 0x8a},
{value: 0x0010, lo: 0x8d, hi: 0xbf},
// Block 0x15, offset 0xab
{value: 0x0010, lo: 0x80, hi: 0xa5},
{value: 0x0014, lo: 0xa6, hi: 0xb0},
{value: 0x0010, lo: 0xb1, hi: 0xb1},
// Block 0x16, offset 0xae
{value: 0x0010, lo: 0x80, hi: 0xaa},
{value: 0x0024, lo: 0xab, hi: 0xb1},
{value: 0x0034, lo: 0xb2, hi: 0xb2},
{value: 0x0024, lo: 0xb3, hi: 0xb3},
{value: 0x0014, lo: 0xb4, hi: 0xb5},
{value: 0x0014, lo: 0xba, hi: 0xba},
// Block 0x17, offset 0xb4
{value: 0x0010, lo: 0x80, hi: 0x95},
{value: 0x0024, lo: 0x96, hi: 0x99},
{value: 0x0014, lo: 0x9a, hi: 0x9a},
{value: 0x0024, lo: 0x9b, hi: 0xa3},
{value: 0x0014, lo: 0xa4, hi: 0xa4},
{value: 0x0024, lo: 0xa5, hi: 0xa7},
{value: 0x0014, lo: 0xa8, hi: 0xa8},
{value: 0x0024, lo: 0xa9, hi: 0xad},
// Block 0x18, offset 0xbc
{value: 0x0010, lo: 0x80, hi: 0x98},
{value: 0x0034, lo: 0x99, hi: 0x9b},
// Block 0x19, offset 0xbe
{value: 0x0010, lo: 0xa0, hi: 0xb4},
// Block 0x1a, offset 0xbf
{value: 0x0034, lo: 0xa3, hi: 0xa3},
{value: 0x0024, lo: 0xa4, hi: 0xa5},
{value: 0x0034, lo: 0xa6, hi: 0xa6},
{value: 0x0024, lo: 0xa7, hi: 0xa8},
{value: 0x0034, lo: 0xa9, hi: 0xa9},
{value: 0x0024, lo: 0xaa, hi: 0xac},
{value: 0x0034, lo: 0xad, hi: 0xb2},
{value: 0x0024, lo: 0xb3, hi: 0xb5},
{value: 0x0034, lo: 0xb6, hi: 0xb6},
{value: 0x0024, lo: 0xb7, hi: 0xb8},
{value: 0x0034, lo: 0xb9, hi: 0xba},
{value: 0x0024, lo: 0xbb, hi: 0xbf},
// Block 0x1b, offset 0xcb
{value: 0x0014, lo: 0x80, hi: 0x82},
{value: 0x0010, lo: 0x83, hi: 0xb9},
{value: 0x0014, lo: 0xba, hi: 0xba},
{value: 0x0010, lo: 0xbb, hi: 0xbb},
{value: 0x0034, lo: 0xbc, hi: 0xbc},
{value: 0x0010, lo: 0xbd, hi: 0xbf},
// Block 0x1c, offset 0xd1
{value: 0x0010, lo: 0x80, hi: 0x80},
{value: 0x0014, lo: 0x81, hi: 0x88},
{value: 0x0010, lo: 0x89, hi: 0x8c},
{value: 0x0034, lo: 0x8d, hi: 0x8d},
{value: 0x0010, lo: 0x8e, hi: 0x90},
{value: 0x0024, lo: 0x91, hi: 0x91},
{value: 0x0034, lo: 0x92, hi: 0x92},
{value: 0x0024, lo: 0x93, hi: 0x94},
{value: 0x0014, lo: 0x95, hi: 0x97},
{value: 0x0010, lo: 0x98, hi: 0xa1},
{value: 0x0014, lo: 0xa2, hi: 0xa3},
{value: 0x0010, lo: 0xa6, hi: 0xaf},
{value: 0x0014, lo: 0xb1, hi: 0xb1},
{value: 0x0010, lo: 0xb2, hi: 0xbf},
// Block 0x1d, offset 0xdf
{value: 0x0010, lo: 0x80, hi: 0x80},
{value: 0x0014, lo: 0x81, hi: 0x81},
{value: 0x0010, lo: 0x82, hi: 0x83},
{value: 0x0010, lo: 0x85, hi: 0x8c},
{value: 0x0010, lo: 0x8f, hi: 0x90},
{value: 0x0010, lo: 0x93, hi: 0xa8},
{value: 0x0010, lo: 0xaa, hi: 0xb0},
{value: 0x0010, lo: 0xb2, hi: 0xb2},
{value: 0x0010, lo: 0xb6, hi: 0xb9},
{value: 0x0034, lo: 0xbc, hi: 0xbc},
{value: 0x0010, lo: 0xbd, hi: 0xbf},
// Block 0x1e, offset 0xea
{value: 0x0010, lo: 0x80, hi: 0x80},
{value: 0x0014, lo: 0x81, hi: 0x84},
{value: 0x0010, lo: 0x87, hi: 0x88},
{value: 0x0010, lo: 0x8b, hi: 0x8c},
{value: 0x0034, lo: 0x8d, hi: 0x8d},
{value: 0x0010, lo: 0x8e, hi: 0x8e},
{value: 0x0010, lo: 0x97, hi: 0x97},
{value: 0x0010, lo: 0x9c, hi: 0x9d},
{value: 0x0010, lo: 0x9f, hi: 0xa1},
{value: 0x0014, lo: 0xa2, hi: 0xa3},
{value: 0x0010, lo: 0xa6, hi: 0xb1},
// Block 0x1f, offset 0xf5
{value: 0x0014, lo: 0x81, hi: 0x82},
{value: 0x0010, lo: 0x83, hi: 0x83},
{value: 0x0010, lo: 0x85, hi: 0x8a},
{value: 0x0010, lo: 0x8f, hi: 0x90},
{value: 0x0010, lo: 0x93, hi: 0xa8},
{value: 0x0010, lo: 0xaa, hi: 0xb0},
{value: 0x0010, lo: 0xb2, hi: 0xb3},
{value: 0x0010, lo: 0xb5, hi: 0xb6},
{value: 0x0010, lo: 0xb8, hi: 0xb9},
{value: 0x0034, lo: 0xbc, hi: 0xbc},
{value: 0x0010, lo: 0xbe, hi: 0xbf},
// Block 0x20, offset 0x100
{value: 0x0010, lo: 0x80, hi: 0x80},
{value: 0x0014, lo: 0x81, hi: 0x82},
{value: 0x0014, lo: 0x87, hi: 0x88},
{value: 0x0014, lo: 0x8b, hi: 0x8c},
{value: 0x0034, lo: 0x8d, hi: 0x8d},
{value: 0x0014, lo: 0x91, hi: 0x91},
{value: 0x0010, lo: 0x99, hi: 0x9c},
{value: 0x0010, lo: 0x9e, hi: 0x9e},
{value: 0x0010, lo: 0xa6, hi: 0xaf},
{value: 0x0014, lo: 0xb0, hi: 0xb1},
{value: 0x0010, lo: 0xb2, hi: 0xb4},
{value: 0x0014, lo: 0xb5, hi: 0xb5},
// Block 0x21, offset 0x10c
{value: 0x0014, lo: 0x81, hi: 0x82},
{value: 0x0010, lo: 0x83, hi: 0x83},
{value: 0x0010, lo: 0x85, hi: 0x8d},
{value: 0x0010, lo: 0x8f, hi: 0x91},
{value: 0x0010, lo: 0x93, hi: 0xa8},
{value: 0x0010, lo: 0xaa, hi: 0xb0},
{value: 0x0010, lo: 0xb2, hi: 0xb3},
{value: 0x0010, lo: 0xb5, hi: 0xb9},
{value: 0x0034, lo: 0xbc, hi: 0xbc},
{value: 0x0010, lo: 0xbd, hi: 0xbf},
// Block 0x22, offset 0x116
{value: 0x0010, lo: 0x80, hi: 0x80},
{value: 0x0014, lo: 0x81, hi: 0x85},
{value: 0x0014, lo: 0x87, hi: 0x88},
{value: 0x0010, lo: 0x89, hi: 0x89},
{value: 0x0010, lo: 0x8b, hi: 0x8c},
{value: 0x0034, lo: 0x8d, hi: 0x8d},
{value: 0x0010, lo: 0x90, hi: 0x90},
{value: 0x0010, lo: 0xa0, hi: 0xa1},
{value: 0x0014, lo: 0xa2, hi: 0xa3},
{value: 0x0010, lo: 0xa6, hi: 0xaf},
{value: 0x0010, lo: 0xb9, hi: 0xb9},
// Block 0x23, offset 0x121
{value: 0x0014, lo: 0x81, hi: 0x81},
{value: 0x0010, lo: 0x82, hi: 0x83},
{value: 0x0010, lo: 0x85, hi: 0x8c},
{value: 0x0010, lo: 0x8f, hi: 0x90},
{value: 0x0010, lo: 0x93, hi: 0xa8},
{value: 0x0010, lo: 0xaa, hi: 0xb0},
{value: 0x0010, lo: 0xb2, hi: 0xb3},
{value: 0x0010, lo: 0xb5, hi: 0xb9},
{value: 0x0034, lo: 0xbc, hi: 0xbc},
{value: 0x0010, lo: 0xbd, hi: 0xbe},
{value: 0x0014, lo: 0xbf, hi: 0xbf},
// Block 0x24, offset 0x12c
{value: 0x0010, lo: 0x80, hi: 0x80},
{value: 0x0014, lo: 0x81, hi: 0x84},
{value: 0x0010, lo: 0x87, hi: 0x88},
{value: 0x0010, lo: 0x8b, hi: 0x8c},
{value: 0x0034, lo: 0x8d, hi: 0x8d},
{value: 0x0014, lo: 0x96, hi: 0x96},
{value: 0x0010, lo: 0x97, hi: 0x97},
{value: 0x0010, lo: 0x9c, hi: 0x9d},
{value: 0x0010, lo: 0x9f, hi: 0xa1},
{value: 0x0014, lo: 0xa2, hi: 0xa3},
{value: 0x0010, lo: 0xa6, hi: 0xaf},
{value: 0x0010, lo: 0xb1, hi: 0xb1},
// Block 0x25, offset 0x138
{value: 0x0014, lo: 0x82, hi: 0x82},
{value: 0x0010, lo: 0x83, hi: 0x83},
{value: 0x0010, lo: 0x85, hi: 0x8a},
{value: 0x0010, lo: 0x8e, hi: 0x90},
{value: 0x0010, lo: 0x92, hi: 0x95},
{value: 0x0010, lo: 0x99, hi: 0x9a},
{value: 0x0010, lo: 0x9c, hi: 0x9c},
{value: 0x0010, lo: 0x9e, hi: 0x9f},
{value: 0x0010, lo: 0xa3, hi: 0xa4},
{value: 0x0010, lo: 0xa8, hi: 0xaa},
{value: 0x0010, lo: 0xae, hi: 0xb9},
{value: 0x0010, lo: 0xbe, hi: 0xbf},
// Block 0x26, offset 0x144
{value: 0x0014, lo: 0x80, hi: 0x80},
{value: 0x0010, lo: 0x81, hi: 0x82},
{value: 0x0010, lo: 0x86, hi: 0x88},
{value: 0x0010, lo: 0x8a, hi: 0x8c},
{value: 0x0034, lo: 0x8d, hi: 0x8d},
{value: 0x0010, lo: 0x90, hi: 0x90},
{value: 0x0010, lo: 0x97, hi: 0x97},
{value: 0x0010, lo: 0xa6, hi: 0xaf},
// Block 0x27, offset 0x14c
{value: 0x0014, lo: 0x80, hi: 0x80},
{value: 0x0010, lo: 0x81, hi: 0x83},
{value: 0x0010, lo: 0x85, hi: 0x8c},
{value: 0x0010, lo: 0x8e, hi: 0x90},
{value: 0x0010, lo: 0x92, hi: 0xa8},
{value: 0x0010, lo: 0xaa, hi: 0xb9},
{value: 0x0010, lo: 0xbd, hi: 0xbd},
{value: 0x0014, lo: 0xbe, hi: 0xbf},
// Block 0x28, offset 0x154
{value: 0x0014, lo: 0x80, hi: 0x80},
{value: 0x0010, lo: 0x81, hi: 0x84},
{value: 0x0014, lo: 0x86, hi: 0x88},
{value: 0x0014, lo: 0x8a, hi: 0x8c},
{value: 0x0034, lo: 0x8d, hi: 0x8d},
{value: 0x0034, lo: 0x95, hi: 0x96},
{value: 0x0010, lo: 0x98, hi: 0x9a},
{value: 0x0010, lo: 0xa0, hi: 0xa1},
{value: 0x0014, lo: 0xa2, hi: 0xa3},
{value: 0x0010, lo: 0xa6, hi: 0xaf},
// Block 0x29, offset 0x15e
{value: 0x0014, lo: 0x81, hi: 0x81},
{value: 0x0010, lo: 0x82, hi: 0x83},
{value: 0x0010, lo: 0x85, hi: 0x8c},
{value: 0x0010, lo: 0x8e, hi: 0x90},
{value: 0x0010, lo: 0x92, hi: 0xa8},
{value: 0x0010, lo: 0xaa, hi: 0xb3},
{value: 0x0010, lo: 0xb5, hi: 0xb9},
{value: 0x0034, lo: 0xbc, hi: 0xbc},
{value: 0x0010, lo: 0xbd, hi: 0xbe},
{value: 0x0014, lo: 0xbf, hi: 0xbf},
// Block 0x2a, offset 0x168
{value: 0x0010, lo: 0x80, hi: 0x84},
{value: 0x0014, lo: 0x86, hi: 0x86},
{value: 0x0010, lo: 0x87, hi: 0x88},
{value: 0x0010, lo: 0x8a, hi: 0x8b},
{value: 0x0014, lo: 0x8c, hi: 0x8c},
{value: 0x0034, lo: 0x8d, hi: 0x8d},
{value: 0x0010, lo: 0x95, hi: 0x96},
{value: 0x0010, lo: 0x9e, hi: 0x9e},
{value: 0x0010, lo: 0xa0, hi: 0xa1},
{value: 0x0014, lo: 0xa2, hi: 0xa3},
{value: 0x0010, lo: 0xa6, hi: 0xaf},
{value: 0x0010, lo: 0xb1, hi: 0xb2},
// Block 0x2b, offset 0x174
{value: 0x0014, lo: 0x81, hi: 0x81},
{value: 0x0010, lo: 0x82, hi: 0x83},
{value: 0x0010, lo: 0x85, hi: 0x8c},
{value: 0x0010, lo: 0x8e, hi: 0x90},
{value: 0x0010, lo: 0x92, hi: 0xba},
{value: 0x0010, lo: 0xbd, hi: 0xbf},
// Block 0x2c, offset 0x17a
{value: 0x0010, lo: 0x80, hi: 0x80},
{value: 0x0014, lo: 0x81, hi: 0x84},
{value: 0x0010, lo: 0x86, hi: 0x88},
{value: 0x0010, lo: 0x8a, hi: 0x8c},
{value: 0x0034, lo: 0x8d, hi: 0x8d},
{value: 0x0010, lo: 0x8e, hi: 0x8e},
{value: 0x0010, lo: 0x97, hi: 0x97},
{value: 0x0010, lo: 0x9f, hi: 0xa1},
{value: 0x0014, lo: 0xa2, hi: 0xa3},
{value: 0x0010, lo: 0xa6, hi: 0xaf},
{value: 0x0010, lo: 0xba, hi: 0xbf},
// Block 0x2d, offset 0x185
{value: 0x0010, lo: 0x82, hi: 0x83},
{value: 0x0010, lo: 0x85, hi: 0x96},
{value: 0x0010, lo: 0x9a, hi: 0xb1},
{value: 0x0010, lo: 0xb3, hi: 0xbb},
{value: 0x0010, lo: 0xbd, hi: 0xbd},
// Block 0x2e, offset 0x18a
{value: 0x0010, lo: 0x80, hi: 0x86},
{value: 0x0034, lo: 0x8a, hi: 0x8a},
{value: 0x0010, lo: 0x8f, hi: 0x91},
{value: 0x0014, lo: 0x92, hi: 0x94},
{value: 0x0014, lo: 0x96, hi: 0x96},
{value: 0x0010, lo: 0x98, hi: 0x9f},
{value: 0x0010, lo: 0xa6, hi: 0xaf},
{value: 0x0010, lo: 0xb2, hi: 0xb3},
// Block 0x2f, offset 0x192
{value: 0x0014, lo: 0xb1, hi: 0xb1},
{value: 0x0014, lo: 0xb4, hi: 0xb7},
{value: 0x0034, lo: 0xb8, hi: 0xba},
// Block 0x30, offset 0x195
{value: 0x0004, lo: 0x86, hi: 0x86},
{value: 0x0014, lo: 0x87, hi: 0x87},
{value: 0x0034, lo: 0x88, hi: 0x8b},
{value: 0x0014, lo: 0x8c, hi: 0x8e},
{value: 0x0010, lo: 0x90, hi: 0x99},
// Block 0x31, offset 0x19a
{value: 0x0014, lo: 0xb1, hi: 0xb1},
{value: 0x0014, lo: 0xb4, hi: 0xb7},
{value: 0x0034, lo: 0xb8, hi: 0xb9},
{value: 0x0014, lo: 0xbb, hi: 0xbc},
// Block 0x32, offset 0x19e
{value: 0x0004, lo: 0x86, hi: 0x86},
{value: 0x0034, lo: 0x88, hi: 0x8b},
{value: 0x0014, lo: 0x8c, hi: 0x8d},
{value: 0x0010, lo: 0x90, hi: 0x99},
// Block 0x33, offset 0x1a2
{value: 0x0010, lo: 0x80, hi: 0x80},
{value: 0x0034, lo: 0x98, hi: 0x99},
{value: 0x0010, lo: 0xa0, hi: 0xa9},
{value: 0x0034, lo: 0xb5, hi: 0xb5},
{value: 0x0034, lo: 0xb7, hi: 0xb7},
{value: 0x0034, lo: 0xb9, hi: 0xb9},
{value: 0x0010, lo: 0xbe, hi: 0xbf},
// Block 0x34, offset 0x1a9
{value: 0x0010, lo: 0x80, hi: 0x87},
{value: 0x0010, lo: 0x89, hi: 0xac},
{value: 0x0034, lo: 0xb1, hi: 0xb2},
{value: 0x0014, lo: 0xb3, hi: 0xb3},
{value: 0x0034, lo: 0xb4, hi: 0xb4},
{value: 0x0014, lo: 0xb5, hi: 0xb9},
{value: 0x0034, lo: 0xba, hi: 0xbd},
{value: 0x0014, lo: 0xbe, hi: 0xbe},
{value: 0x0010, lo: 0xbf, hi: 0xbf},
// Block 0x35, offset 0x1b2
{value: 0x0034, lo: 0x80, hi: 0x80},
{value: 0x0014, lo: 0x81, hi: 0x81},
{value: 0x0024, lo: 0x82, hi: 0x83},
{value: 0x0034, lo: 0x84, hi: 0x84},
{value: 0x0024, lo: 0x86, hi: 0x87},
{value: 0x0010, lo: 0x88, hi: 0x8c},
{value: 0x0014, lo: 0x8d, hi: 0x97},
{value: 0x0014, lo: 0x99, hi: 0xbc},
// Block 0x36, offset 0x1ba
{value: 0x0034, lo: 0x86, hi: 0x86},
// Block 0x37, offset 0x1bb
{value: 0x0010, lo: 0xab, hi: 0xac},
{value: 0x0014, lo: 0xad, hi: 0xb0},
{value: 0x0010, lo: 0xb1, hi: 0xb1},
{value: 0x0014, lo: 0xb2, hi: 0xb6},
{value: 0x0034, lo: 0xb7, hi: 0xb7},
{value: 0x0010, lo: 0xb8, hi: 0xb8},
{value: 0x0034, lo: 0xb9, hi: 0xba},
{value: 0x0010, lo: 0xbb, hi: 0xbc},
{value: 0x0014, lo: 0xbd, hi: 0xbe},
// Block 0x38, offset 0x1c4
{value: 0x0010, lo: 0x80, hi: 0x89},
{value: 0x0010, lo: 0x96, hi: 0x97},
{value: 0x0014, lo: 0x98, hi: 0x99},
{value: 0x0014, lo: 0x9e, hi: 0xa0},
{value: 0x0010, lo: 0xa2, hi: 0xa4},
{value: 0x0010, lo: 0xa7, hi: 0xad},
{value: 0x0014, lo: 0xb1, hi: 0xb4},
// Block 0x39, offset 0x1cb
{value: 0x0014, lo: 0x82, hi: 0x82},
{value: 0x0010, lo: 0x83, hi: 0x84},
{value: 0x0014, lo: 0x85, hi: 0x86},
{value: 0x0010, lo: 0x87, hi: 0x8c},
{value: 0x0034, lo: 0x8d, hi: 0x8d},
{value: 0x0010, lo: 0x8f, hi: 0x9c},
{value: 0x0014, lo: 0x9d, hi: 0x9d},
{value: 0x4253, lo: 0xa0, hi: 0xbf},
// Block 0x3a, offset 0x1d3
{value: 0x4453, lo: 0x80, hi: 0x85},
{value: 0x4453, lo: 0x87, hi: 0x87},
{value: 0x4453, lo: 0x8d, hi: 0x8d},
{value: 0x0010, lo: 0x90, hi: 0xba},
{value: 0x0014, lo: 0xbc, hi: 0xbc},
{value: 0x0010, lo: 0xbd, hi: 0xbf},
// Block 0x3b, offset 0x1d9
{value: 0x0010, lo: 0x80, hi: 0x88},
{value: 0x0010, lo: 0x8a, hi: 0x8d},
{value: 0x0010, lo: 0x90, hi: 0x96},
{value: 0x0010, lo: 0x98, hi: 0x98},
{value: 0x0010, lo: 0x9a, hi: 0x9d},
{value: 0x0010, lo: 0xa0, hi: 0xbf},
// Block 0x3c, offset 0x1df
{value: 0x0010, lo: 0x80, hi: 0x88},
{value: 0x0010, lo: 0x8a, hi: 0x8d},
{value: 0x0010, lo: 0x90, hi: 0xb0},
{value: 0x0010, lo: 0xb2, hi: 0xb5},
{value: 0x0010, lo: 0xb8, hi: 0xbe},
// Block 0x3d, offset 0x1e4
{value: 0x0010, lo: 0x80, hi: 0x80},
{value: 0x0010, lo: 0x82, hi: 0x85},
{value: 0x0010, lo: 0x88, hi: 0x96},
{value: 0x0010, lo: 0x98, hi: 0xbf},
// Block 0x3e, offset 0x1e8
{value: 0x0010, lo: 0x80, hi: 0x90},
{value: 0x0010, lo: 0x92, hi: 0x95},
{value: 0x0010, lo: 0x98, hi: 0xbf},
// Block 0x3f, offset 0x1eb
{value: 0x0010, lo: 0x80, hi: 0x9a},
{value: 0x0024, lo: 0x9d, hi: 0x9f},
// Block 0x40, offset 0x1ed
{value: 0x0010, lo: 0x80, hi: 0x8f},
{value: 0x4653, lo: 0xa0, hi: 0xaf},
{value: 0x4853, lo: 0xb0, hi: 0xbf},
// Block 0x41, offset 0x1f0
{value: 0x4a53, lo: 0x80, hi: 0x8f},
{value: 0x4c53, lo: 0x90, hi: 0x9f},
{value: 0x4a53, lo: 0xa0, hi: 0xaf},
{value: 0x0413, lo: 0xb0, hi: 0xb5},
{value: 0x0412, lo: 0xb8, hi: 0xbd},
// Block 0x42, offset 0x1f5
{value: 0x0010, lo: 0x81, hi: 0xbf},
// Block 0x43, offset 0x1f6
{value: 0x0010, lo: 0x80, hi: 0xac},
{value: 0x0010, lo: 0xaf, hi: 0xbf},
// Block 0x44, offset 0x1f8
{value: 0x0010, lo: 0x81, hi: 0x9a},
{value: 0x0010, lo: 0xa0, hi: 0xbf},
// Block 0x45, offset 0x1fa
{value: 0x0010, lo: 0x80, hi: 0xaa},
{value: 0x0010, lo: 0xae, hi: 0xb8},
// Block 0x46, offset 0x1fc
{value: 0x0010, lo: 0x80, hi: 0x8c},
{value: 0x0010, lo: 0x8e, hi: 0x91},
{value: 0x0014, lo: 0x92, hi: 0x93},
{value: 0x0034, lo: 0x94, hi: 0x94},
{value: 0x0010, lo: 0xa0, hi: 0xb1},
{value: 0x0014, lo: 0xb2, hi: 0xb3},
{value: 0x0034, lo: 0xb4, hi: 0xb4},
// Block 0x47, offset 0x203
{value: 0x0010, lo: 0x80, hi: 0x91},
{value: 0x0014, lo: 0x92, hi: 0x93},
{value: 0x0010, lo: 0xa0, hi: 0xac},
{value: 0x0010, lo: 0xae, hi: 0xb0},
{value: 0x0014, lo: 0xb2, hi: 0xb3},
// Block 0x48, offset 0x208
{value: 0x0014, lo: 0xb4, hi: 0xb5},
{value: 0x0010, lo: 0xb6, hi: 0xb6},
{value: 0x0014, lo: 0xb7, hi: 0xbd},
{value: 0x0010, lo: 0xbe, hi: 0xbf},
// Block 0x49, offset 0x20c
{value: 0x0010, lo: 0x80, hi: 0x85},
{value: 0x0014, lo: 0x86, hi: 0x86},
{value: 0x0010, lo: 0x87, hi: 0x88},
{value: 0x0014, lo: 0x89, hi: 0x91},
{value: 0x0034, lo: 0x92, hi: 0x92},
{value: 0x0014, lo: 0x93, hi: 0x93},
{value: 0x0004, lo: 0x97, hi: 0x97},
{value: 0x0024, lo: 0x9d, hi: 0x9d},
{value: 0x0010, lo: 0xa0, hi: 0xa9},
// Block 0x4a, offset 0x215
{value: 0x0014, lo: 0x8b, hi: 0x8e},
{value: 0x0010, lo: 0x90, hi: 0x99},
{value: 0x0010, lo: 0xa0, hi: 0xbf},
// Block 0x4b, offset 0x218
{value: 0x0010, lo: 0x80, hi: 0x82},
{value: 0x0014, lo: 0x83, hi: 0x83},
{value: 0x0010, lo: 0x84, hi: 0xb7},
// Block 0x4c, offset 0x21b
{value: 0x0010, lo: 0x80, hi: 0xa8},
{value: 0x0034, lo: 0xa9, hi: 0xa9},
{value: 0x0010, lo: 0xaa, hi: 0xaa},
{value: 0x0010, lo: 0xb0, hi: 0xbf},
// Block 0x4d, offset 0x21f
{value: 0x0010, lo: 0x80, hi: 0xb5},
// Block 0x4e, offset 0x220
{value: 0x0010, lo: 0x80, hi: 0x9e},
{value: 0x0014, lo: 0xa0, hi: 0xa2},
{value: 0x0010, lo: 0xa3, hi: 0xa6},
{value: 0x0014, lo: 0xa7, hi: 0xa8},
{value: 0x0010, lo: 0xa9, hi: 0xab},
{value: 0x0010, lo: 0xb0, hi: 0xb1},
{value: 0x0014, lo: 0xb2, hi: 0xb2},
{value: 0x0010, lo: 0xb3, hi: 0xb8},
{value: 0x0034, lo: 0xb9, hi: 0xb9},
{value: 0x0024, lo: 0xba, hi: 0xba},
{value: 0x0034, lo: 0xbb, hi: 0xbb},
// Block 0x4f, offset 0x22b
{value: 0x0010, lo: 0x86, hi: 0x8f},
// Block 0x50, offset 0x22c
{value: 0x0010, lo: 0x90, hi: 0x99},
// Block 0x51, offset 0x22d
{value: 0x0010, lo: 0x80, hi: 0x96},
{value: 0x0024, lo: 0x97, hi: 0x97},
{value: 0x0034, lo: 0x98, hi: 0x98},
{value: 0x0010, lo: 0x99, hi: 0x9a},
{value: 0x0014, lo: 0x9b, hi: 0x9b},
// Block 0x52, offset 0x232
{value: 0x0010, lo: 0x95, hi: 0x95},
{value: 0x0014, lo: 0x96, hi: 0x96},
{value: 0x0010, lo: 0x97, hi: 0x97},
{value: 0x0014, lo: 0x98, hi: 0x9e},
{value: 0x0034, lo: 0xa0, hi: 0xa0},
{value: 0x0010, lo: 0xa1, hi: 0xa1},
{value: 0x0014, lo: 0xa2, hi: 0xa2},
{value: 0x0010, lo: 0xa3, hi: 0xa4},
{value: 0x0014, lo: 0xa5, hi: 0xac},
{value: 0x0010, lo: 0xad, hi: 0xb2},
{value: 0x0014, lo: 0xb3, hi: 0xb4},
{value: 0x0024, lo: 0xb5, hi: 0xbc},
{value: 0x0034, lo: 0xbf, hi: 0xbf},
// Block 0x53, offset 0x23f
{value: 0x0010, lo: 0x80, hi: 0x89},
{value: 0x0010, lo: 0x90, hi: 0x99},
{value: 0x0004, lo: 0xa7, hi: 0xa7},
{value: 0x0024, lo: 0xb0, hi: 0xb4},
{value: 0x0034, lo: 0xb5, hi: 0xba},
{value: 0x0024, lo: 0xbb, hi: 0xbc},
{value: 0x0034, lo: 0xbd, hi: 0xbd},
{value: 0x0014, lo: 0xbe, hi: 0xbe},
// Block 0x54, offset 0x247
{value: 0x0014, lo: 0x80, hi: 0x83},
{value: 0x0010, lo: 0x84, hi: 0xb3},
{value: 0x0034, lo: 0xb4, hi: 0xb4},
{value: 0x0010, lo: 0xb5, hi: 0xb5},
{value: 0x0014, lo: 0xb6, hi: 0xba},
{value: 0x0010, lo: 0xbb, hi: 0xbb},
{value: 0x0014, lo: 0xbc, hi: 0xbc},
{value: 0x0010, lo: 0xbd, hi: 0xbf},
// Block 0x55, offset 0x24f
{value: 0x0010, lo: 0x80, hi: 0x81},
{value: 0x0014, lo: 0x82, hi: 0x82},
{value: 0x0010, lo: 0x83, hi: 0x83},
{value: 0x0030, lo: 0x84, hi: 0x84},
{value: 0x0010, lo: 0x85, hi: 0x8b},
{value: 0x0010, lo: 0x90, hi: 0x99},
{value: 0x0024, lo: 0xab, hi: 0xab},
{value: 0x0034, lo: 0xac, hi: 0xac},
{value: 0x0024, lo: 0xad, hi: 0xb3},
// Block 0x56, offset 0x258
{value: 0x0014, lo: 0x80, hi: 0x81},
{value: 0x0010, lo: 0x82, hi: 0xa1},
{value: 0x0014, lo: 0xa2, hi: 0xa5},
{value: 0x0010, lo: 0xa6, hi: 0xa7},
{value: 0x0014, lo: 0xa8, hi: 0xa9},
{value: 0x0030, lo: 0xaa, hi: 0xaa},
{value: 0x0034, lo: 0xab, hi: 0xab},
{value: 0x0014, lo: 0xac, hi: 0xad},
{value: 0x0010, lo: 0xae, hi: 0xbf},
// Block 0x57, offset 0x261
{value: 0x0010, lo: 0x80, hi: 0xa5},
{value: 0x0034, lo: 0xa6, hi: 0xa6},
{value: 0x0010, lo: 0xa7, hi: 0xa7},
{value: 0x0014, lo: 0xa8, hi: 0xa9},
{value: 0x0010, lo: 0xaa, hi: 0xac},
{value: 0x0014, lo: 0xad, hi: 0xad},
{value: 0x0010, lo: 0xae, hi: 0xae},
{value: 0x0014, lo: 0xaf, hi: 0xb1},
{value: 0x0030, lo: 0xb2, hi: 0xb3},
// Block 0x58, offset 0x26a
{value: 0x0010, lo: 0x80, hi: 0xab},
{value: 0x0014, lo: 0xac, hi: 0xb3},
{value: 0x0010, lo: 0xb4, hi: 0xb5},
{value: 0x0014, lo: 0xb6, hi: 0xb6},
{value: 0x0034, lo: 0xb7, hi: 0xb7},
// Block 0x59, offset 0x26f
{value: 0x0010, lo: 0x80, hi: 0x89},
{value: 0x0010, lo: 0x8d, hi: 0xb7},
{value: 0x0014, lo: 0xb8, hi: 0xbd},
// Block 0x5a, offset 0x272
{value: 0x0024, lo: 0x90, hi: 0x92},
{value: 0x0034, lo: 0x94, hi: 0x99},
{value: 0x0024, lo: 0x9a, hi: 0x9b},
{value: 0x0034, lo: 0x9c, hi: 0x9f},
{value: 0x0024, lo: 0xa0, hi: 0xa0},
{value: 0x0010, lo: 0xa1, hi: 0xa1},
{value: 0x0034, lo: 0xa2, hi: 0xa8},
{value: 0x0010, lo: 0xa9, hi: 0xac},
{value: 0x0034, lo: 0xad, hi: 0xad},
{value: 0x0010, lo: 0xae, hi: 0xb3},
{value: 0x0024, lo: 0xb4, hi: 0xb4},
{value: 0x0010, lo: 0xb5, hi: 0xb6},
{value: 0x0024, lo: 0xb8, hi: 0xb9},
// Block 0x5b, offset 0x27f
{value: 0x0012, lo: 0x80, hi: 0xab},
{value: 0x0015, lo: 0xac, hi: 0xbf},
// Block 0x5c, offset 0x281
{value: 0x0015, lo: 0x80, hi: 0xaa},
{value: 0x0012, lo: 0xab, hi: 0xb7},
{value: 0x0015, lo: 0xb8, hi: 0xb8},
{value: 0x4e52, lo: 0xb9, hi: 0xb9},
{value: 0x0012, lo: 0xba, hi: 0xbc},
{value: 0x5052, lo: 0xbd, hi: 0xbd},
{value: 0x0012, lo: 0xbe, hi: 0xbf},
// Block 0x5d, offset 0x288
{value: 0x0012, lo: 0x80, hi: 0x9a},
{value: 0x0015, lo: 0x9b, hi: 0xbf},
// Block 0x5e, offset 0x28a
{value: 0x0024, lo: 0x80, hi: 0x81},
{value: 0x0034, lo: 0x82, hi: 0x82},
{value: 0x0024, lo: 0x83, hi: 0x89},
{value: 0x0034, lo: 0x8a, hi: 0x8a},
{value: 0x0024, lo: 0x8b, hi: 0x8c},
{value: 0x0034, lo: 0x8d, hi: 0x90},
{value: 0x0024, lo: 0x91, hi: 0xb5},
{value: 0x0034, lo: 0xbc, hi: 0xbd},
{value: 0x0024, lo: 0xbe, hi: 0xbe},
{value: 0x0034, lo: 0xbf, hi: 0xbf},
// Block 0x5f, offset 0x294
{value: 0x0097, lo: 0x80, hi: 0xbf},
// Block 0x60, offset 0x295
{value: 0x0097, lo: 0x80, hi: 0x95},
{value: 0x1b1a, lo: 0x96, hi: 0x96},
{value: 0x1bba, lo: 0x97, hi: 0x97},
{value: 0x1c5a, lo: 0x98, hi: 0x98},
{value: 0x1cfa, lo: 0x99, hi: 0x99},
{value: 0x1d9a, lo: 0x9a, hi: 0x9a},
{value: 0x51d2, lo: 0x9b, hi: 0x9b},
{value: 0x0012, lo: 0x9c, hi: 0x9d},
{value: 0x1e3b, lo: 0x9e, hi: 0x9e},
{value: 0x0012, lo: 0x9f, hi: 0x9f},
{value: 0x0097, lo: 0xa0, hi: 0xbf},
// Block 0x61, offset 0x2a0
{value: 0x0412, lo: 0x80, hi: 0x87},
{value: 0x0413, lo: 0x88, hi: 0x8f},
{value: 0x0412, lo: 0x90, hi: 0x95},
{value: 0x0413, lo: 0x98, hi: 0x9d},
{value: 0x0412, lo: 0xa0, hi: 0xa7},
{value: 0x0413, lo: 0xa8, hi: 0xaf},
{value: 0x0412, lo: 0xb0, hi: 0xb7},
{value: 0x0413, lo: 0xb8, hi: 0xbf},
// Block 0x62, offset 0x2a8
{value: 0x0004, lo: 0x8b, hi: 0x8b},
{value: 0x0014, lo: 0x8c, hi: 0x8f},
{value: 0x0014, lo: 0x98, hi: 0x99},
{value: 0x0014, lo: 0xa4, hi: 0xa4},
{value: 0x0014, lo: 0xa7, hi: 0xa7},
{value: 0x0014, lo: 0xaa, hi: 0xae},
{value: 0x0010, lo: 0xbf, hi: 0xbf},
// Block 0x63, offset 0x2af
{value: 0x0010, lo: 0x80, hi: 0x80},
{value: 0x0010, lo: 0x94, hi: 0x94},
{value: 0x0014, lo: 0xa0, hi: 0xa4},
{value: 0x0014, lo: 0xa6, hi: 0xaf},
{value: 0x0015, lo: 0xb1, hi: 0xb1},
{value: 0x0015, lo: 0xbf, hi: 0xbf},
// Block 0x64, offset 0x2b5
{value: 0x0015, lo: 0x90, hi: 0x9c},
// Block 0x65, offset 0x2b6
{value: 0x0024, lo: 0x90, hi: 0x91},
{value: 0x0034, lo: 0x92, hi: 0x93},
{value: 0x0024, lo: 0x94, hi: 0x97},
{value: 0x0034, lo: 0x98, hi: 0x9a},
{value: 0x0024, lo: 0x9b, hi: 0x9c},
{value: 0x0014, lo: 0x9d, hi: 0xa0},
{value: 0x0024, lo: 0xa1, hi: 0xa1},
{value: 0x0014, lo: 0xa2, hi: 0xa4},
{value: 0x0034, lo: 0xa5, hi: 0xa6},
{value: 0x0024, lo: 0xa7, hi: 0xa7},
{value: 0x0034, lo: 0xa8, hi: 0xa8},
{value: 0x0024, lo: 0xa9, hi: 0xa9},
{value: 0x0034, lo: 0xaa, hi: 0xaf},
{value: 0x0024, lo: 0xb0, hi: 0xb0},
// Block 0x66, offset 0x2c4
{value: 0x0016, lo: 0x85, hi: 0x86},
{value: 0x0012, lo: 0x87, hi: 0x89},
{value: 0x5c52, lo: 0x8e, hi: 0x8e},
{value: 0x0813, lo: 0xa0, hi: 0xaf},
{value: 0x0812, lo: 0xb0, hi: 0xbf},
// Block 0x67, offset 0x2c9
{value: 0x0010, lo: 0x80, hi: 0x82},
{value: 0x0396, lo: 0x83, hi: 0x84},
{value: 0x0010, lo: 0x85, hi: 0x88},
// Block 0x68, offset 0x2cc
{value: 0x5dd3, lo: 0xb6, hi: 0xb7},
{value: 0x3bd3, lo: 0xb8, hi: 0xb9},
{value: 0x5f53, lo: 0xba, hi: 0xbb},
{value: 0x3bd3, lo: 0xbc, hi: 0xbd},
{value: 0x5dd3, lo: 0xbe, hi: 0xbf},
// Block 0x69, offset 0x2d1
{value: 0x1813, lo: 0x80, hi: 0x8f},
{value: 0x3d53, lo: 0x90, hi: 0x9f},
{value: 0x60d3, lo: 0xa0, hi: 0xae},
{value: 0x1812, lo: 0xb0, hi: 0xbf},
// Block 0x6a, offset 0x2d5
{value: 0x0097, lo: 0x80, hi: 0xa3},
{value: 0x0012, lo: 0xa4, hi: 0xa4},
{value: 0x0396, lo: 0xab, hi: 0xac},
{value: 0x0196, lo: 0xad, hi: 0xae},
{value: 0x0024, lo: 0xaf, hi: 0xb1},
{value: 0x0097, lo: 0xb2, hi: 0xb3},
// Block 0x6b, offset 0x2db
{value: 0x4252, lo: 0x80, hi: 0x9f},
{value: 0x4452, lo: 0xa0, hi: 0xa5},
{value: 0x4452, lo: 0xa7, hi: 0xa7},
{value: 0x4452, lo: 0xad, hi: 0xad},
{value: 0x0010, lo: 0xb0, hi: 0xbf},
// Block 0x6c, offset 0x2e0
{value: 0x0010, lo: 0x80, hi: 0xa7},
{value: 0x0014, lo: 0xaf, hi: 0xaf},
{value: 0x0034, lo: 0xbf, hi: 0xbf},
// Block 0x6d, offset 0x2e3
{value: 0x0010, lo: 0x80, hi: 0x96},
{value: 0x0010, lo: 0xa0, hi: 0xa6},
{value: 0x0010, lo: 0xa8, hi: 0xae},
{value: 0x0010, lo: 0xb0, hi: 0xb6},
{value: 0x0010, lo: 0xb8, hi: 0xbe},
// Block 0x6e, offset 0x2e8
{value: 0x0010, lo: 0x80, hi: 0x86},
{value: 0x0010, lo: 0x88, hi: 0x8e},
{value: 0x0010, lo: 0x90, hi: 0x96},
{value: 0x0010, lo: 0x98, hi: 0x9e},
{value: 0x0024, lo: 0xa0, hi: 0xbf},
// Block 0x6f, offset 0x2ed
{value: 0x0014, lo: 0xaf, hi: 0xaf},
// Block 0x70, offset 0x2ee
{value: 0x0014, lo: 0x85, hi: 0x85},
{value: 0x0034, lo: 0xaa, hi: 0xad},
{value: 0x0030, lo: 0xae, hi: 0xaf},
{value: 0x0004, lo: 0xb1, hi: 0xb5},
{value: 0x0014, lo: 0xbb, hi: 0xbb},
{value: 0x0010, lo: 0xbc, hi: 0xbc},
// Block 0x71, offset 0x2f4
{value: 0x0034, lo: 0x99, hi: 0x9a},
{value: 0x0004, lo: 0x9b, hi: 0x9e},
// Block 0x72, offset 0x2f6
{value: 0x0004, lo: 0xbc, hi: 0xbe},
// Block 0x73, offset 0x2f7
{value: 0x0010, lo: 0x85, hi: 0xad},
{value: 0x0010, lo: 0xb1, hi: 0xbf},
// Block 0x74, offset 0x2f9
{value: 0x0010, lo: 0x80, hi: 0x8e},
{value: 0x0010, lo: 0xa0, hi: 0xba},
// Block 0x75, offset 0x2fb
{value: 0x0010, lo: 0x80, hi: 0x94},
{value: 0x0014, lo: 0x95, hi: 0x95},
{value: 0x0010, lo: 0x96, hi: 0xbf},
// Block 0x76, offset 0x2fe
{value: 0x0010, lo: 0x80, hi: 0x8c},
// Block 0x77, offset 0x2ff
{value: 0x0010, lo: 0x90, hi: 0xb7},
{value: 0x0014, lo: 0xb8, hi: 0xbd},
// Block 0x78, offset 0x301
{value: 0x0010, lo: 0x80, hi: 0x8b},
{value: 0x0014, lo: 0x8c, hi: 0x8c},
{value: 0x0010, lo: 0x90, hi: 0xab},
// Block 0x79, offset 0x304
{value: 0x0097, lo: 0x80, hi: 0xad},
{value: 0x0010, lo: 0xae, hi: 0xae},
{value: 0x0024, lo: 0xaf, hi: 0xaf},
{value: 0x0014, lo: 0xb0, hi: 0xb2},
{value: 0x0024, lo: 0xb4, hi: 0xbd},
{value: 0x0014, lo: 0xbf, hi: 0xbf},
// Block 0x7a, offset 0x30a
{value: 0x0097, lo: 0x80, hi: 0x9b},
{value: 0x0015, lo: 0x9c, hi: 0x9d},
{value: 0x0024, lo: 0x9e, hi: 0x9f},
{value: 0x0010, lo: 0xa0, hi: 0xbf},
// Block 0x7b, offset 0x30e
{value: 0x0010, lo: 0x80, hi: 0xaf},
{value: 0x0024, lo: 0xb0, hi: 0xb1},
// Block 0x7c, offset 0x310
{value: 0x0004, lo: 0x80, hi: 0x96},
{value: 0x0014, lo: 0x97, hi: 0x9f},
{value: 0x0004, lo: 0xa0, hi: 0xa1},
{value: 0x0097, lo: 0xa2, hi: 0xaf},
{value: 0x0012, lo: 0xb0, hi: 0xb1},
{value: 0x0097, lo: 0xb2, hi: 0xbf},
// Block 0x7d, offset 0x316
{value: 0x0097, lo: 0x80, hi: 0xaf},
{value: 0x0015, lo: 0xb0, hi: 0xb0},
{value: 0x0012, lo: 0xb1, hi: 0xb8},
{value: 0x0196, lo: 0xb9, hi: 0xba},
{value: 0x0396, lo: 0xbb, hi: 0xbc},
{value: 0x4e53, lo: 0xbd, hi: 0xbd},
{value: 0x0097, lo: 0xbe, hi: 0xbf},
// Block 0x7e, offset 0x31d
{value: 0x0010, lo: 0xb7, hi: 0xb7},
{value: 0x0015, lo: 0xb8, hi: 0xb9},
{value: 0x0012, lo: 0xba, hi: 0xba},
{value: 0x0010, lo: 0xbb, hi: 0xbf},
// Block 0x7f, offset 0x321
{value: 0x0010, lo: 0x80, hi: 0x81},
{value: 0x0014, lo: 0x82, hi: 0x82},
{value: 0x0010, lo: 0x83, hi: 0x85},
{value: 0x0034, lo: 0x86, hi: 0x86},
{value: 0x0010, lo: 0x87, hi: 0x8a},
{value: 0x0014, lo: 0x8b, hi: 0x8b},
{value: 0x0010, lo: 0x8c, hi: 0xa4},
{value: 0x0014, lo: 0xa5, hi: 0xa6},
{value: 0x0010, lo: 0xa7, hi: 0xa7},
// Block 0x80, offset 0x32a
{value: 0x0010, lo: 0x80, hi: 0xb3},
// Block 0x81, offset 0x32b
{value: 0x0010, lo: 0x80, hi: 0x83},
{value: 0x0034, lo: 0x84, hi: 0x84},
{value: 0x0010, lo: 0x90, hi: 0x99},
{value: 0x0024, lo: 0xa0, hi: 0xb1},
{value: 0x0010, lo: 0xb2, hi: 0xb7},
{value: 0x0010, lo: 0xbb, hi: 0xbb},
{value: 0x0010, lo: 0xbd, hi: 0xbd},
// Block 0x82, offset 0x332
{value: 0x0010, lo: 0x80, hi: 0xa5},
{value: 0x0014, lo: 0xa6, hi: 0xaa},
{value: 0x0034, lo: 0xab, hi: 0xad},
{value: 0x0010, lo: 0xb0, hi: 0xbf},
// Block 0x83, offset 0x336
{value: 0x0010, lo: 0x80, hi: 0x86},
{value: 0x0014, lo: 0x87, hi: 0x91},
{value: 0x0010, lo: 0x92, hi: 0x92},
{value: 0x0030, lo: 0x93, hi: 0x93},
{value: 0x0010, lo: 0xa0, hi: 0xbc},
// Block 0x84, offset 0x33b
{value: 0x0014, lo: 0x80, hi: 0x82},
{value: 0x0010, lo: 0x83, hi: 0xb2},
{value: 0x0034, lo: 0xb3, hi: 0xb3},
{value: 0x0010, lo: 0xb4, hi: 0xb5},
{value: 0x0014, lo: 0xb6, hi: 0xb9},
{value: 0x0010, lo: 0xba, hi: 0xbb},
{value: 0x0014, lo: 0xbc, hi: 0xbc},
{value: 0x0010, lo: 0xbd, hi: 0xbf},
// Block 0x85, offset 0x343
{value: 0x0030, lo: 0x80, hi: 0x80},
{value: 0x0014, lo: 0x8f, hi: 0x8f},
{value: 0x0010, lo: 0x90, hi: 0x99},
{value: 0x0014, lo: 0xa5, hi: 0xa5},
{value: 0x0004, lo: 0xa6, hi: 0xa6},
{value: 0x0010, lo: 0xb0, hi: 0xb9},
// Block 0x86, offset 0x349
{value: 0x0010, lo: 0x80, hi: 0xa8},
{value: 0x0014, lo: 0xa9, hi: 0xae},
{value: 0x0010, lo: 0xaf, hi: 0xb0},
{value: 0x0014, lo: 0xb1, hi: 0xb2},
{value: 0x0010, lo: 0xb3, hi: 0xb4},
{value: 0x0014, lo: 0xb5, hi: 0xb6},
// Block 0x87, offset 0x34f
{value: 0x0010, lo: 0x80, hi: 0x82},
{value: 0x0014, lo: 0x83, hi: 0x83},
{value: 0x0010, lo: 0x84, hi: 0x8b},
{value: 0x0014, lo: 0x8c, hi: 0x8c},
{value: 0x0010, lo: 0x8d, hi: 0x8d},
{value: 0x0010, lo: 0x90, hi: 0x99},
{value: 0x0004, lo: 0xb0, hi: 0xb0},
{value: 0x0010, lo: 0xbb, hi: 0xbb},
{value: 0x0014, lo: 0xbc, hi: 0xbc},
{value: 0x0010, lo: 0xbd, hi: 0xbd},
// Block 0x88, offset 0x359
{value: 0x0024, lo: 0xb0, hi: 0xb0},
{value: 0x0024, lo: 0xb2, hi: 0xb3},
{value: 0x0034, lo: 0xb4, hi: 0xb4},
{value: 0x0024, lo: 0xb7, hi: 0xb8},
{value: 0x0024, lo: 0xbe, hi: 0xbf},
// Block 0x89, offset 0x35e
{value: 0x0024, lo: 0x81, hi: 0x81},
{value: 0x0004, lo: 0x9d, hi: 0x9d},
{value: 0x0010, lo: 0xa0, hi: 0xab},
{value: 0x0014, lo: 0xac, hi: 0xad},
{value: 0x0010, lo: 0xae, hi: 0xaf},
{value: 0x0010, lo: 0xb2, hi: 0xb2},
{value: 0x0014, lo: 0xb3, hi: 0xb4},
{value: 0x0010, lo: 0xb5, hi: 0xb5},
{value: 0x0034, lo: 0xb6, hi: 0xb6},
// Block 0x8a, offset 0x367
{value: 0x0010, lo: 0x81, hi: 0x86},
{value: 0x0010, lo: 0x89, hi: 0x8e},
{value: 0x0010, lo: 0x91, hi: 0x96},
{value: 0x0010, lo: 0xa0, hi: 0xa6},
{value: 0x0010, lo: 0xa8, hi: 0xae},
{value: 0x0012, lo: 0xb0, hi: 0xbf},
// Block 0x8b, offset 0x36d
{value: 0x0012, lo: 0x80, hi: 0x92},
{value: 0x6252, lo: 0x93, hi: 0x93},
{value: 0x0012, lo: 0x94, hi: 0x9a},
{value: 0x0004, lo: 0x9b, hi: 0x9b},
{value: 0x0015, lo: 0x9c, hi: 0x9f},
{value: 0x0012, lo: 0xa0, hi: 0xa5},
{value: 0x4652, lo: 0xb0, hi: 0xbf},
// Block 0x8c, offset 0x374
{value: 0x4852, lo: 0x80, hi: 0x8f},
{value: 0x4a52, lo: 0x90, hi: 0x9f},
{value: 0x4c52, lo: 0xa0, hi: 0xaf},
{value: 0x4a52, lo: 0xb0, hi: 0xbf},
// Block 0x8d, offset 0x378
{value: 0x0010, lo: 0x80, hi: 0xa4},
{value: 0x0014, lo: 0xa5, hi: 0xa5},
{value: 0x0010, lo: 0xa6, hi: 0xa7},
{value: 0x0014, lo: 0xa8, hi: 0xa8},
{value: 0x0010, lo: 0xa9, hi: 0xaa},
{value: 0x0010, lo: 0xac, hi: 0xac},
{value: 0x0034, lo: 0xad, hi: 0xad},
{value: 0x0010, lo: 0xb0, hi: 0xb9},
// Block 0x8e, offset 0x380
{value: 0x0010, lo: 0x80, hi: 0xa3},
{value: 0x0010, lo: 0xb0, hi: 0xbf},
// Block 0x8f, offset 0x382
{value: 0x0010, lo: 0x80, hi: 0x86},
{value: 0x0010, lo: 0x8b, hi: 0xbb},
// Block 0x90, offset 0x384
{value: 0x0010, lo: 0x80, hi: 0x81},
{value: 0x0010, lo: 0x83, hi: 0x84},
{value: 0x0010, lo: 0x86, hi: 0xbf},
// Block 0x91, offset 0x387
{value: 0x0010, lo: 0x80, hi: 0xb1},
{value: 0x0004, lo: 0xb2, hi: 0xbf},
// Block 0x92, offset 0x389
{value: 0x0004, lo: 0x80, hi: 0x81},
{value: 0x0010, lo: 0x93, hi: 0xbf},
// Block 0x93, offset 0x38b
{value: 0x0010, lo: 0x80, hi: 0xbd},
// Block 0x94, offset 0x38c
{value: 0x0010, lo: 0x90, hi: 0xbf},
// Block 0x95, offset 0x38d
{value: 0x0010, lo: 0x80, hi: 0x8f},
{value: 0x0010, lo: 0x92, hi: 0xbf},
// Block 0x96, offset 0x38f
{value: 0x0010, lo: 0x80, hi: 0x87},
{value: 0x0010, lo: 0xb0, hi: 0xbb},
// Block 0x97, offset 0x391
{value: 0x0014, lo: 0x80, hi: 0x8f},
{value: 0x0014, lo: 0x93, hi: 0x93},
{value: 0x0024, lo: 0xa0, hi: 0xa6},
{value: 0x0034, lo: 0xa7, hi: 0xad},
{value: 0x0024, lo: 0xae, hi: 0xaf},
{value: 0x0010, lo: 0xb3, hi: 0xb4},
// Block 0x98, offset 0x397
{value: 0x0010, lo: 0x8d, hi: 0x8f},
{value: 0x0014, lo: 0x92, hi: 0x92},
{value: 0x0014, lo: 0x95, hi: 0x95},
{value: 0x0010, lo: 0xb0, hi: 0xb4},
{value: 0x0010, lo: 0xb6, hi: 0xbf},
// Block 0x99, offset 0x39c
{value: 0x0010, lo: 0x80, hi: 0xbc},
{value: 0x0014, lo: 0xbf, hi: 0xbf},
// Block 0x9a, offset 0x39e
{value: 0x0014, lo: 0x87, hi: 0x87},
{value: 0x0014, lo: 0x8e, hi: 0x8e},
{value: 0x0014, lo: 0x9a, hi: 0x9a},
{value: 0x32d3, lo: 0xa1, hi: 0xba},
{value: 0x0004, lo: 0xbe, hi: 0xbe},
{value: 0x0010, lo: 0xbf, hi: 0xbf},
// Block 0x9b, offset 0x3a4
{value: 0x0004, lo: 0x80, hi: 0x80},
{value: 0x32d2, lo: 0x81, hi: 0x9a},
{value: 0x0004, lo: 0xb0, hi: 0xb0},
// Block 0x9c, offset 0x3a7
{value: 0x0014, lo: 0x9e, hi: 0x9f},
{value: 0x0010, lo: 0xa0, hi: 0xbe},
// Block 0x9d, offset 0x3a9
{value: 0x0010, lo: 0x82, hi: 0x87},
{value: 0x0010, lo: 0x8a, hi: 0x8f},
{value: 0x0010, lo: 0x92, hi: 0x97},
{value: 0x0010, lo: 0x9a, hi: 0x9c},
{value: 0x0004, lo: 0xa3, hi: 0xa3},
{value: 0x0014, lo: 0xb9, hi: 0xbb},
// Block 0x9e, offset 0x3af
{value: 0x0010, lo: 0x80, hi: 0x8b},
{value: 0x0010, lo: 0x8d, hi: 0xa6},
{value: 0x0010, lo: 0xa8, hi: 0xba},
{value: 0x0010, lo: 0xbc, hi: 0xbd},
{value: 0x0010, lo: 0xbf, hi: 0xbf},
// Block 0x9f, offset 0x3b4
{value: 0x0010, lo: 0x80, hi: 0x8d},
{value: 0x0010, lo: 0x90, hi: 0x9d},
// Block 0xa0, offset 0x3b6
{value: 0x0010, lo: 0x80, hi: 0xba},
// Block 0xa1, offset 0x3b7
{value: 0x0010, lo: 0x80, hi: 0xb4},
// Block 0xa2, offset 0x3b8
{value: 0x0034, lo: 0xbd, hi: 0xbd},
// Block 0xa3, offset 0x3b9
{value: 0x0010, lo: 0x80, hi: 0x9c},
{value: 0x0010, lo: 0xa0, hi: 0xbf},
// Block 0xa4, offset 0x3bb
{value: 0x0010, lo: 0x80, hi: 0x90},
{value: 0x0034, lo: 0xa0, hi: 0xa0},
// Block 0xa5, offset 0x3bd
{value: 0x0010, lo: 0x80, hi: 0x9f},
{value: 0x0010, lo: 0xb0, hi: 0xbf},
// Block 0xa6, offset 0x3bf
{value: 0x0010, lo: 0x80, hi: 0x8a},
{value: 0x0010, lo: 0x90, hi: 0xb5},
{value: 0x0024, lo: 0xb6, hi: 0xba},
// Block 0xa7, offset 0x3c2
{value: 0x0010, lo: 0x80, hi: 0x9d},
{value: 0x0010, lo: 0xa0, hi: 0xbf},
// Block 0xa8, offset 0x3c4
{value: 0x0010, lo: 0x80, hi: 0x83},
{value: 0x0010, lo: 0x88, hi: 0x8f},
{value: 0x0010, lo: 0x91, hi: 0x95},
// Block 0xa9, offset 0x3c7
{value: 0x1413, lo: 0x80, hi: 0x87},
{value: 0x1c13, lo: 0x88, hi: 0x8f},
{value: 0x1413, lo: 0x90, hi: 0x97},
{value: 0x63d3, lo: 0x98, hi: 0x9f},
{value: 0x6553, lo: 0xa0, hi: 0xa7},
{value: 0x1412, lo: 0xa8, hi: 0xaf},
{value: 0x1c12, lo: 0xb0, hi: 0xb7},
{value: 0x1412, lo: 0xb8, hi: 0xbf},
// Block 0xaa, offset 0x3cf
{value: 0x63d2, lo: 0x80, hi: 0x87},
{value: 0x6552, lo: 0x88, hi: 0x8f},
{value: 0x0010, lo: 0x90, hi: 0xbf},
// Block 0xab, offset 0x3d2
{value: 0x0010, lo: 0x80, hi: 0x9d},
{value: 0x0010, lo: 0xa0, hi: 0xa9},
// Block 0xac, offset 0x3d4
{value: 0x0010, lo: 0x80, hi: 0xa7},
{value: 0x0010, lo: 0xb0, hi: 0xbf},
// Block 0xad, offset 0x3d6
{value: 0x0010, lo: 0x80, hi: 0xa3},
// Block 0xae, offset 0x3d7
{value: 0x0010, lo: 0x80, hi: 0xb6},
// Block 0xaf, offset 0x3d8
{value: 0x0010, lo: 0x80, hi: 0x95},
{value: 0x0010, lo: 0xa0, hi: 0xa7},
// Block 0xb0, offset 0x3da
{value: 0x0010, lo: 0x80, hi: 0x85},
{value: 0x0010, lo: 0x88, hi: 0x88},
{value: 0x0010, lo: 0x8a, hi: 0xb5},
{value: 0x0010, lo: 0xb7, hi: 0xb8},
{value: 0x0010, lo: 0xbc, hi: 0xbc},
{value: 0x0010, lo: 0xbf, hi: 0xbf},
// Block 0xb1, offset 0x3e0
{value: 0x0010, lo: 0x80, hi: 0x95},
{value: 0x0010, lo: 0xa0, hi: 0xb6},
// Block 0xb2, offset 0x3e2
{value: 0x0010, lo: 0x80, hi: 0x9e},
// Block 0xb3, offset 0x3e3
{value: 0x0010, lo: 0xa0, hi: 0xb2},
{value: 0x0010, lo: 0xb4, hi: 0xb5},
// Block 0xb4, offset 0x3e5
{value: 0x0010, lo: 0x80, hi: 0x95},
{value: 0x0010, lo: 0xa0, hi: 0xb9},
// Block 0xb5, offset 0x3e7
{value: 0x0010, lo: 0x80, hi: 0xb7},
{value: 0x0010, lo: 0xbe, hi: 0xbf},
// Block 0xb6, offset 0x3e9
{value: 0x0010, lo: 0x80, hi: 0x80},
{value: 0x0014, lo: 0x81, hi: 0x83},
{value: 0x0014, lo: 0x85, hi: 0x86},
{value: 0x0014, lo: 0x8c, hi: 0x8c},
{value: 0x0034, lo: 0x8d, hi: 0x8d},
{value: 0x0014, lo: 0x8e, hi: 0x8e},
{value: 0x0024, lo: 0x8f, hi: 0x8f},
{value: 0x0010, lo: 0x90, hi: 0x93},
{value: 0x0010, lo: 0x95, hi: 0x97},
{value: 0x0010, lo: 0x99, hi: 0xb3},
{value: 0x0024, lo: 0xb8, hi: 0xb8},
{value: 0x0034, lo: 0xb9, hi: 0xba},
{value: 0x0034, lo: 0xbf, hi: 0xbf},
// Block 0xb7, offset 0x3f6
{value: 0x0010, lo: 0xa0, hi: 0xbc},
// Block 0xb8, offset 0x3f7
{value: 0x0010, lo: 0x80, hi: 0x9c},
// Block 0xb9, offset 0x3f8
{value: 0x0010, lo: 0x80, hi: 0x87},
{value: 0x0010, lo: 0x89, hi: 0xa4},
{value: 0x0024, lo: 0xa5, hi: 0xa5},
{value: 0x0034, lo: 0xa6, hi: 0xa6},
// Block 0xba, offset 0x3fc
{value: 0x0010, lo: 0x80, hi: 0x95},
{value: 0x0010, lo: 0xa0, hi: 0xb2},
// Block 0xbb, offset 0x3fe
{value: 0x0010, lo: 0x80, hi: 0x91},
// Block 0xbc, offset 0x3ff
{value: 0x0010, lo: 0x80, hi: 0x88},
// Block 0xbd, offset 0x400
{value: 0x2e53, lo: 0x80, hi: 0xb2},
// Block 0xbe, offset 0x401
{value: 0x2e52, lo: 0x80, hi: 0xb2},
// Block 0xbf, offset 0x402
{value: 0x0010, lo: 0x80, hi: 0x80},
{value: 0x0014, lo: 0x81, hi: 0x81},
{value: 0x0010, lo: 0x82, hi: 0xb7},
{value: 0x0014, lo: 0xb8, hi: 0xbf},
// Block 0xc0, offset 0x406
{value: 0x0014, lo: 0x80, hi: 0x85},
{value: 0x0034, lo: 0x86, hi: 0x86},
{value: 0x0010, lo: 0xa6, hi: 0xaf},
{value: 0x0034, lo: 0xbf, hi: 0xbf},
// Block 0xc1, offset 0x40a
{value: 0x0014, lo: 0x80, hi: 0x81},
{value: 0x0010, lo: 0x82, hi: 0xb2},
{value: 0x0014, lo: 0xb3, hi: 0xb6},
{value: 0x0010, lo: 0xb7, hi: 0xb8},
{value: 0x0034, lo: 0xb9, hi: 0xba},
{value: 0x0014, lo: 0xbd, hi: 0xbd},
// Block 0xc2, offset 0x410
{value: 0x0010, lo: 0x90, hi: 0xa8},
{value: 0x0010, lo: 0xb0, hi: 0xb9},
// Block 0xc3, offset 0x412
{value: 0x0024, lo: 0x80, hi: 0x82},
{value: 0x0010, lo: 0x83, hi: 0xa6},
{value: 0x0014, lo: 0xa7, hi: 0xab},
{value: 0x0010, lo: 0xac, hi: 0xac},
{value: 0x0014, lo: 0xad, hi: 0xb2},
{value: 0x0034, lo: 0xb3, hi: 0xb4},
{value: 0x0010, lo: 0xb6, hi: 0xbf},
// Block 0xc4, offset 0x419
{value: 0x0010, lo: 0x90, hi: 0xb2},
{value: 0x0034, lo: 0xb3, hi: 0xb3},
{value: 0x0010, lo: 0xb6, hi: 0xb6},
// Block 0xc5, offset 0x41c
{value: 0x0014, lo: 0x80, hi: 0x81},
{value: 0x0010, lo: 0x82, hi: 0xb5},
{value: 0x0014, lo: 0xb6, hi: 0xbe},
{value: 0x0010, lo: 0xbf, hi: 0xbf},
// Block 0xc6, offset 0x420
{value: 0x0030, lo: 0x80, hi: 0x80},
{value: 0x0010, lo: 0x81, hi: 0x84},
{value: 0x0034, lo: 0x8a, hi: 0x8a},
{value: 0x0014, lo: 0x8b, hi: 0x8c},
{value: 0x0010, lo: 0x90, hi: 0x9a},
{value: 0x0010, lo: 0x9c, hi: 0x9c},
// Block 0xc7, offset 0x426
{value: 0x0010, lo: 0x80, hi: 0x91},
{value: 0x0010, lo: 0x93, hi: 0xae},
{value: 0x0014, lo: 0xaf, hi: 0xb1},
{value: 0x0010, lo: 0xb2, hi: 0xb3},
{value: 0x0014, lo: 0xb4, hi: 0xb4},
{value: 0x0030, lo: 0xb5, hi: 0xb5},
{value: 0x0034, lo: 0xb6, hi: 0xb6},
{value: 0x0014, lo: 0xb7, hi: 0xb7},
// Block 0xc8, offset 0x42e
{value: 0x0010, lo: 0x80, hi: 0x86},
{value: 0x0010, lo: 0x88, hi: 0x88},
{value: 0x0010, lo: 0x8a, hi: 0x8d},
{value: 0x0010, lo: 0x8f, hi: 0x9d},
{value: 0x0010, lo: 0x9f, hi: 0xa8},
{value: 0x0010, lo: 0xb0, hi: 0xbf},
// Block 0xc9, offset 0x434
{value: 0x0010, lo: 0x80, hi: 0x9e},
{value: 0x0014, lo: 0x9f, hi: 0x9f},
{value: 0x0010, lo: 0xa0, hi: 0xa2},
{value: 0x0014, lo: 0xa3, hi: 0xa8},
{value: 0x0034, lo: 0xa9, hi: 0xaa},
{value: 0x0010, lo: 0xb0, hi: 0xb9},
// Block 0xca, offset 0x43a
{value: 0x0014, lo: 0x80, hi: 0x81},
{value: 0x0010, lo: 0x82, hi: 0x83},
{value: 0x0010, lo: 0x85, hi: 0x8c},
{value: 0x0010, lo: 0x8f, hi: 0x90},
{value: 0x0010, lo: 0x93, hi: 0xa8},
{value: 0x0010, lo: 0xaa, hi: 0xb0},
{value: 0x0010, lo: 0xb2, hi: 0xb3},
{value: 0x0010, lo: 0xb5, hi: 0xb9},
{value: 0x0034, lo: 0xbc, hi: 0xbc},
{value: 0x0010, lo: 0xbd, hi: 0xbf},
// Block 0xcb, offset 0x444
{value: 0x0014, lo: 0x80, hi: 0x80},
{value: 0x0010, lo: 0x81, hi: 0x84},
{value: 0x0010, lo: 0x87, hi: 0x88},
{value: 0x0010, lo: 0x8b, hi: 0x8c},
{value: 0x0030, lo: 0x8d, hi: 0x8d},
{value: 0x0010, lo: 0x90, hi: 0x90},
{value: 0x0010, lo: 0x97, hi: 0x97},
{value: 0x0010, lo: 0x9d, hi: 0xa3},
{value: 0x0024, lo: 0xa6, hi: 0xac},
{value: 0x0024, lo: 0xb0, hi: 0xb4},
// Block 0xcc, offset 0x44e
{value: 0x0010, lo: 0x80, hi: 0xb2},
{value: 0x0014, lo: 0xb3, hi: 0xb8},
{value: 0x0010, lo: 0xb9, hi: 0xb9},
{value: 0x0014, lo: 0xba, hi: 0xba},
{value: 0x0010, lo: 0xbb, hi: 0xbe},
{value: 0x0014, lo: 0xbf, hi: 0xbf},
// Block 0xcd, offset 0x454
{value: 0x0014, lo: 0x80, hi: 0x80},
{value: 0x0010, lo: 0x81, hi: 0x81},
{value: 0x0034, lo: 0x82, hi: 0x83},
{value: 0x0010, lo: 0x84, hi: 0x85},
{value: 0x0010, lo: 0x87, hi: 0x87},
{value: 0x0010, lo: 0x90, hi: 0x99},
// Block 0xce, offset 0x45a
{value: 0x0010, lo: 0x80, hi: 0xb1},
{value: 0x0014, lo: 0xb2, hi: 0xb5},
{value: 0x0010, lo: 0xb8, hi: 0xbb},
{value: 0x0014, lo: 0xbc, hi: 0xbd},
{value: 0x0010, lo: 0xbe, hi: 0xbe},
{value: 0x0034, lo: 0xbf, hi: 0xbf},
// Block 0xcf, offset 0x460
{value: 0x0034, lo: 0x80, hi: 0x80},
{value: 0x0010, lo: 0x98, hi: 0x9b},
{value: 0x0014, lo: 0x9c, hi: 0x9d},
// Block 0xd0, offset 0x463
{value: 0x0010, lo: 0x80, hi: 0xb2},
{value: 0x0014, lo: 0xb3, hi: 0xba},
{value: 0x0010, lo: 0xbb, hi: 0xbc},
{value: 0x0014, lo: 0xbd, hi: 0xbd},
{value: 0x0010, lo: 0xbe, hi: 0xbe},
{value: 0x0034, lo: 0xbf, hi: 0xbf},
// Block 0xd1, offset 0x469
{value: 0x0014, lo: 0x80, hi: 0x80},
{value: 0x0010, lo: 0x84, hi: 0x84},
{value: 0x0010, lo: 0x90, hi: 0x99},
// Block 0xd2, offset 0x46c
{value: 0x0010, lo: 0x80, hi: 0xaa},
{value: 0x0014, lo: 0xab, hi: 0xab},
{value: 0x0010, lo: 0xac, hi: 0xac},
{value: 0x0014, lo: 0xad, hi: 0xad},
{value: 0x0010, lo: 0xae, hi: 0xaf},
{value: 0x0014, lo: 0xb0, hi: 0xb5},
{value: 0x0030, lo: 0xb6, hi: 0xb6},
{value: 0x0034, lo: 0xb7, hi: 0xb7},
// Block 0xd3, offset 0x474
{value: 0x0010, lo: 0x80, hi: 0x89},
// Block 0xd4, offset 0x475
{value: 0x0014, lo: 0x9d, hi: 0x9f},
{value: 0x0010, lo: 0xa0, hi: 0xa1},
{value: 0x0014, lo: 0xa2, hi: 0xa5},
{value: 0x0010, lo: 0xa6, hi: 0xa6},
{value: 0x0014, lo: 0xa7, hi: 0xaa},
{value: 0x0034, lo: 0xab, hi: 0xab},
{value: 0x0010, lo: 0xb0, hi: 0xb9},
// Block 0xd5, offset 0x47c
{value: 0x32d3, lo: 0xa0, hi: 0xbf},
// Block 0xd6, offset 0x47d
{value: 0x32d2, lo: 0x80, hi: 0x9f},
{value: 0x0010, lo: 0xa0, hi: 0xa9},
{value: 0x0010, lo: 0xbf, hi: 0xbf},
// Block 0xd7, offset 0x480
{value: 0x0010, lo: 0x80, hi: 0xb8},
// Block 0xd8, offset 0x481
{value: 0x0010, lo: 0x80, hi: 0x99},
// Block 0xd9, offset 0x482
{value: 0x0010, lo: 0x80, hi: 0xae},
// Block 0xda, offset 0x483
{value: 0x0010, lo: 0x80, hi: 0x83},
// Block 0xdb, offset 0x484
{value: 0x0010, lo: 0x80, hi: 0x86},
// Block 0xdc, offset 0x485
{value: 0x0010, lo: 0x80, hi: 0x9e},
{value: 0x0010, lo: 0xa0, hi: 0xa9},
// Block 0xdd, offset 0x487
{value: 0x0010, lo: 0x90, hi: 0xad},
{value: 0x0034, lo: 0xb0, hi: 0xb4},
// Block 0xde, offset 0x489
{value: 0x0010, lo: 0x80, hi: 0xaf},
{value: 0x0024, lo: 0xb0, hi: 0xb6},
// Block 0xdf, offset 0x48b
{value: 0x0014, lo: 0x80, hi: 0x83},
{value: 0x0010, lo: 0x90, hi: 0x99},
{value: 0x0010, lo: 0xa3, hi: 0xb7},
{value: 0x0010, lo: 0xbd, hi: 0xbf},
// Block 0xe0, offset 0x48f
{value: 0x0010, lo: 0x80, hi: 0x8f},
// Block 0xe1, offset 0x490
{value: 0x0010, lo: 0x80, hi: 0x84},
{value: 0x0010, lo: 0x90, hi: 0xbe},
// Block 0xe2, offset 0x492
{value: 0x0014, lo: 0x8f, hi: 0x9f},
// Block 0xe3, offset 0x493
{value: 0x0010, lo: 0x80, hi: 0xaa},
{value: 0x0010, lo: 0xb0, hi: 0xbc},
// Block 0xe4, offset 0x495
{value: 0x0010, lo: 0x80, hi: 0x88},
{value: 0x0010, lo: 0x90, hi: 0x99},
{value: 0x0014, lo: 0x9d, hi: 0x9d},
{value: 0x0034, lo: 0x9e, hi: 0x9e},
{value: 0x0014, lo: 0xa0, hi: 0xa3},
// Block 0xe5, offset 0x49a
{value: 0x0030, lo: 0xa5, hi: 0xa6},
{value: 0x0034, lo: 0xa7, hi: 0xa9},
{value: 0x0030, lo: 0xad, hi: 0xb2},
{value: 0x0014, lo: 0xb3, hi: 0xba},
{value: 0x0034, lo: 0xbb, hi: 0xbf},
// Block 0xe6, offset 0x49f
{value: 0x0034, lo: 0x80, hi: 0x82},
{value: 0x0024, lo: 0x85, hi: 0x89},
{value: 0x0034, lo: 0x8a, hi: 0x8b},
{value: 0x0024, lo: 0xaa, hi: 0xad},
// Block 0xe7, offset 0x4a3
{value: 0x0024, lo: 0x82, hi: 0x84},
// Block 0xe8, offset 0x4a4
{value: 0x0013, lo: 0x80, hi: 0x99},
{value: 0x0012, lo: 0x9a, hi: 0xb3},
{value: 0x0013, lo: 0xb4, hi: 0xbf},
// Block 0xe9, offset 0x4a7
{value: 0x0013, lo: 0x80, hi: 0x8d},
{value: 0x0012, lo: 0x8e, hi: 0x94},
{value: 0x0012, lo: 0x96, hi: 0xa7},
{value: 0x0013, lo: 0xa8, hi: 0xbf},
// Block 0xea, offset 0x4ab
{value: 0x0013, lo: 0x80, hi: 0x81},
{value: 0x0012, lo: 0x82, hi: 0x9b},
{value: 0x0013, lo: 0x9c, hi: 0x9c},
{value: 0x0013, lo: 0x9e, hi: 0x9f},
{value: 0x0013, lo: 0xa2, hi: 0xa2},
{value: 0x0013, lo: 0xa5, hi: 0xa6},
{value: 0x0013, lo: 0xa9, hi: 0xac},
{value: 0x0013, lo: 0xae, hi: 0xb5},
{value: 0x0012, lo: 0xb6, hi: 0xb9},
{value: 0x0012, lo: 0xbb, hi: 0xbb},
{value: 0x0012, lo: 0xbd, hi: 0xbf},
// Block 0xeb, offset 0x4b6
{value: 0x0012, lo: 0x80, hi: 0x83},
{value: 0x0012, lo: 0x85, hi: 0x8f},
{value: 0x0013, lo: 0x90, hi: 0xa9},
{value: 0x0012, lo: 0xaa, hi: 0xbf},
// Block 0xec, offset 0x4ba
{value: 0x0012, lo: 0x80, hi: 0x83},
{value: 0x0013, lo: 0x84, hi: 0x85},
{value: 0x0013, lo: 0x87, hi: 0x8a},
{value: 0x0013, lo: 0x8d, hi: 0x94},
{value: 0x0013, lo: 0x96, hi: 0x9c},
{value: 0x0012, lo: 0x9e, hi: 0xb7},
{value: 0x0013, lo: 0xb8, hi: 0xb9},
{value: 0x0013, lo: 0xbb, hi: 0xbe},
// Block 0xed, offset 0x4c2
{value: 0x0013, lo: 0x80, hi: 0x84},
{value: 0x0013, lo: 0x86, hi: 0x86},
{value: 0x0013, lo: 0x8a, hi: 0x90},
{value: 0x0012, lo: 0x92, hi: 0xab},
{value: 0x0013, lo: 0xac, hi: 0xbf},
// Block 0xee, offset 0x4c7
{value: 0x0013, lo: 0x80, hi: 0x85},
{value: 0x0012, lo: 0x86, hi: 0x9f},
{value: 0x0013, lo: 0xa0, hi: 0xb9},
{value: 0x0012, lo: 0xba, hi: 0xbf},
// Block 0xef, offset 0x4cb
{value: 0x0012, lo: 0x80, hi: 0x93},
{value: 0x0013, lo: 0x94, hi: 0xad},
{value: 0x0012, lo: 0xae, hi: 0xbf},
// Block 0xf0, offset 0x4ce
{value: 0x0012, lo: 0x80, hi: 0x87},
{value: 0x0013, lo: 0x88, hi: 0xa1},
{value: 0x0012, lo: 0xa2, hi: 0xbb},
{value: 0x0013, lo: 0xbc, hi: 0xbf},
// Block 0xf1, offset 0x4d2
{value: 0x0013, lo: 0x80, hi: 0x95},
{value: 0x0012, lo: 0x96, hi: 0xaf},
{value: 0x0013, lo: 0xb0, hi: 0xbf},
// Block 0xf2, offset 0x4d5
{value: 0x0013, lo: 0x80, hi: 0x89},
{value: 0x0012, lo: 0x8a, hi: 0xa5},
{value: 0x0013, lo: 0xa8, hi: 0xbf},
// Block 0xf3, offset 0x4d8
{value: 0x0013, lo: 0x80, hi: 0x80},
{value: 0x0012, lo: 0x82, hi: 0x9a},
{value: 0x0012, lo: 0x9c, hi: 0xa1},
{value: 0x0013, lo: 0xa2, hi: 0xba},
{value: 0x0012, lo: 0xbc, hi: 0xbf},
// Block 0xf4, offset 0x4dd
{value: 0x0012, lo: 0x80, hi: 0x94},
{value: 0x0012, lo: 0x96, hi: 0x9b},
{value: 0x0013, lo: 0x9c, hi: 0xb4},
{value: 0x0012, lo: 0xb6, hi: 0xbf},
// Block 0xf5, offset 0x4e1
{value: 0x0012, lo: 0x80, hi: 0x8e},
{value: 0x0012, lo: 0x90, hi: 0x95},
{value: 0x0013, lo: 0x96, hi: 0xae},
{value: 0x0012, lo: 0xb0, hi: 0xbf},
// Block 0xf6, offset 0x4e5
{value: 0x0012, lo: 0x80, hi: 0x88},
{value: 0x0012, lo: 0x8a, hi: 0x8f},
{value: 0x0013, lo: 0x90, hi: 0xa8},
{value: 0x0012, lo: 0xaa, hi: 0xbf},
// Block 0xf7, offset 0x4e9
{value: 0x0012, lo: 0x80, hi: 0x82},
{value: 0x0012, lo: 0x84, hi: 0x89},
{value: 0x0017, lo: 0x8a, hi: 0x8b},
{value: 0x0010, lo: 0x8e, hi: 0xbf},
// Block 0xf8, offset 0x4ed
{value: 0x0014, lo: 0x80, hi: 0xb6},
{value: 0x0014, lo: 0xbb, hi: 0xbf},
// Block 0xf9, offset 0x4ef
{value: 0x0014, lo: 0x80, hi: 0xac},
{value: 0x0014, lo: 0xb5, hi: 0xb5},
// Block 0xfa, offset 0x4f1
{value: 0x0014, lo: 0x84, hi: 0x84},
{value: 0x0014, lo: 0x9b, hi: 0x9f},
{value: 0x0014, lo: 0xa1, hi: 0xaf},
// Block 0xfb, offset 0x4f4
{value: 0x0010, lo: 0x80, hi: 0x84},
{value: 0x0034, lo: 0x90, hi: 0x96},
// Block 0xfc, offset 0x4f6
{value: 0x0010, lo: 0x80, hi: 0x83},
{value: 0x0010, lo: 0x85, hi: 0x9f},
{value: 0x0010, lo: 0xa1, hi: 0xa2},
{value: 0x0010, lo: 0xa4, hi: 0xa4},
{value: 0x0010, lo: 0xa7, hi: 0xa7},
{value: 0x0010, lo: 0xa9, hi: 0xb2},
{value: 0x0010, lo: 0xb4, hi: 0xb7},
{value: 0x0010, lo: 0xb9, hi: 0xb9},
{value: 0x0010, lo: 0xbb, hi: 0xbb},
// Block 0xfd, offset 0x4ff
{value: 0x0010, lo: 0x80, hi: 0x89},
{value: 0x0010, lo: 0x8b, hi: 0x9b},
{value: 0x0010, lo: 0xa1, hi: 0xa3},
{value: 0x0010, lo: 0xa5, hi: 0xa9},
{value: 0x0010, lo: 0xab, hi: 0xbb},
// Block 0xfe, offset 0x504
{value: 0x0013, lo: 0xb0, hi: 0xbf},
// Block 0xff, offset 0x505
{value: 0x0013, lo: 0x80, hi: 0x89},
{value: 0x0013, lo: 0x90, hi: 0xa9},
{value: 0x0013, lo: 0xb0, hi: 0xbf},
// Block 0x100, offset 0x508
{value: 0x0013, lo: 0x80, hi: 0x89},
// Block 0x101, offset 0x509
{value: 0x0004, lo: 0xbb, hi: 0xbf},
// Block 0x102, offset 0x50a
{value: 0x0014, lo: 0x81, hi: 0x81},
{value: 0x0014, lo: 0xa0, hi: 0xbf},
// Block 0x103, offset 0x50c
{value: 0x0014, lo: 0x80, hi: 0xbf},
// Block 0x104, offset 0x50d
{value: 0x0014, lo: 0x80, hi: 0xaf},
}
// UnicodeVersion is the Unicode version from which the tables in this package are derived.
const UnicodeVersion = "8.0.0"
// xorData: 203 bytes
var xorData = "\x00\f)\x00\x06\a\x00\x01?\x00\x0f\x03\x00\x0f\x12\x00\x0f\x1f\x00\x0f\x1d\x00\x01\x13\x00\x0f\x16\x00\x0f\v\x00\x0f3\x00\x0f7\x00\x01#\x00\x0f?\x00\x0e'\x00\x0f/\x00\x0e>\x00\x0f*\x00\f&\x00\f*\x00\f;\x00\f9\x00\f%\x00\x01\b\x00\x03\r\x00\x03\t\x00\x03\x1c\x00\x02\x06\x00\x02\x02\x00\x02\f\x00\x01\x00\x00\x01\x03\x00\x01\x01\x00\x01 \x00\x01!\x00\x01\x02\x00\x01\t\x00\x013\x00\x016\x00\x01*\x00\x01\x10\x00\x01\f\x00\x03\x10\x00\x036 \x00\x037 \x00\v#\x10\x00\v 0\x00\v!\x10\x00\v!0\x00\v(\x04\x00\x03\x04\x1e\x00\x03;\x00\x03\n\x00\x02:\x00\x02>\x00\x02,\x00\x02\x00\x00\x02\x10\x00\x01<\x00\x01&\x00\x01.\x00\x010\x003 \x00\x01\x18\x00\x01("
// exceptions: 1184 bytes
var exceptions = "\x00\x00\x12SSSs\x00\x18\x00\bI\x00\x18ʼN\x00\bS\x00\x12džDž\x00\x12džDŽ\x00\x12DŽDž\x00\x12ljLj\x00\x12ljLJ\x00\x12LJLj\x00\x12njNj\x00\x12njNJ\x00\x12NJNj\x00\x18\x00\x12dzDz\x00\x12dzDZ\x00\x12DZDz\x00\x18\x00\x18\x00\x18\x00\x18Ɀ\x00\x18\x00\x18\x00\x18\x00\x18\x00\x18\x00\x18\x00\x18\x00\x18\x00\x18\x00\x18\x00\x18\x00\x18\x00\x18\x00\x18\x000Ϊ́\x000Ϋ́\x00$ԵՒԵւ\x00\x18\x00\x18\x00\x18\x00\x18\x00\x18\x00\x10ß\x00 Υ̓\x000Υ̓̀\x000Υ̓́\x000Υ̓͂\x00+ἈΙᾈ\x00+ἉΙᾉ\x00+ἊΙᾊ\x00+ἋΙᾋ\x00+ἌΙᾌ\x00+ἍΙᾍ\x00+ἎΙᾎ\x00+ἏΙᾏ\x00\x1dᾀἈΙ\x00\x1dᾁἉΙ\x00\x1dᾂἊΙ\x00\x1dᾃἋΙ\x00\x1dᾄἌΙ\x00\x1dᾅἍΙ\x00\x1dᾆἎΙ\x00\x1dᾇἏΙ\x00+ἨΙᾘ\x00+ἩΙᾙ\x00+ἪΙᾚ\x00+ἫΙᾛ\x00+ἬΙᾜ\x00+ἭΙᾝ\x00+ἮΙᾞ\x00+ἯΙᾟ\x00\x1dᾐἨΙ\x00\x1dᾑἩΙ\x00\x1dᾒἪΙ\x00\x1dᾓἫΙ\x00\x1dᾔἬΙ\x00\x1dᾕἭΙ\x00\x1dᾖἮΙ\x00\x1dᾗἯΙ\x00+ὨΙᾨ\x00+ὩΙᾩ\x00+ὪΙᾪ\x00+ὫΙᾫ\x00+ὬΙᾬ\x00+ὭΙᾭ\x00+ὮΙᾮ\x00+ὯΙᾯ\x00\x1dᾠὨΙ\x00\x1dᾡὩΙ\x00\x1dᾢὪΙ\x00\x1dᾣὫΙ\x00\x1dᾤὬΙ\x00\x1dᾥὭΙ\x00\x1dᾦὮΙ\x00\x1dᾧὯΙ\x00-ᾺΙᾺͅ\x00#ΑΙᾼ\x00$ΆΙΆͅ\x00 Α͂\x006Α͂Ιᾼ͂\x00\x1cᾳΑΙ\x00\x10Ι\x00-ῊΙῊͅ\x00#ΗΙῌ\x00$ΉΙΉͅ\x00 Η͂\x006Η͂Ιῌ͂\x00\x1cῃΗΙ\x000Ϊ̀\x000Ϊ́\x00 Ι͂\x000Ϊ͂\x000Ϋ̀\x000Ϋ́\x00 Ρ̓\x00 Υ͂\x000Ϋ͂\x00-ῺΙῺͅ\x00#ΩΙῼ\x00$ΏΙΏͅ\x00 Ω͂\x006Ω͂Ιῼ͂\x00\x1cῳΩΙ\x00\x10ω\x00\bk\x00\x10å\x00\x10ɫ\x00\x10ɽ\x00\x10Ⱥ\x00\x10Ⱦ\x00\x10ɑ\x00\x10ɱ\x00\x10ɐ\x00\x10ɒ\x00\x10ȿ\x00\x10ɀ\x00\x10ɥ\x00\x10ɦ\x00\x10ɜ\x00\x10ɡ\x00\x10ɬ\x00\x10ʞ\x00\x10ʇ\x00\x10ʝ\x00\x12FFFf\x00\x12FIFi\x00\x12FLFl\x00\x1bFFIFfi\x00\x1bFFLFfl\x00\x12STSt\x00\x12STSt\x00$ՄՆՄն\x00$ՄԵՄե\x00$ՄԻՄի\x00$ՎՆՎն\x00$ՄԽՄխ"
// Total table size 12514 bytes (12KiB)
// This file was generated by go generate; DO NOT EDIT
package cases
var (
caseIgnorable = map[rune]bool{
0x0027: true,
0x002e: true,
0x003a: true,
0x00b7: true,
0x0387: true,
0x05f4: true,
0x2018: true,
0x2019: true,
0x2024: true,
0x2027: true,
0xfe13: true,
0xfe52: true,
0xfe55: true,
0xff07: true,
0xff0e: true,
0xff1a: true,
}
special = map[rune]struct{ toLower, toTitle, toUpper string }{
0x00df: {"ß", "Ss", "SS"},
0x0130: {"i̇", "İ", "İ"},
0xfb00: {"ff", "Ff", "FF"},
0xfb01: {"fi", "Fi", "FI"},
0xfb02: {"fl", "Fl", "FL"},
0xfb03: {"ffi", "Ffi", "FFI"},
0xfb04: {"ffl", "Ffl", "FFL"},
0xfb05: {"ſt", "St", "ST"},
0xfb06: {"st", "St", "ST"},
0x0587: {"և", "Եւ", "ԵՒ"},
0xfb13: {"ﬓ", "Մն", "ՄՆ"},
0xfb14: {"ﬔ", "Մե", "ՄԵ"},
0xfb15: {"ﬕ", "Մի", "ՄԻ"},
0xfb16: {"ﬖ", "Վն", "ՎՆ"},
0xfb17: {"ﬗ", "Մխ", "ՄԽ"},
0x0149: {"ʼn", "ʼN", "ʼN"},
0x0390: {"ΐ", "Ϊ́", "Ϊ́"},
0x03b0: {"ΰ", "Ϋ́", "Ϋ́"},
0x01f0: {"ǰ", "J̌", "J̌"},
0x1e96: {"ẖ", "H̱", "H̱"},
0x1e97: {"ẗ", "T̈", "T̈"},
0x1e98: {"ẘ", "W̊", "W̊"},
0x1e99: {"ẙ", "Y̊", "Y̊"},
0x1e9a: {"ẚ", "Aʾ", "Aʾ"},
0x1f50: {"ὐ", "Υ̓", "Υ̓"},
0x1f52: {"ὒ", "Υ̓̀", "Υ̓̀"},
0x1f54: {"ὔ", "Υ̓́", "Υ̓́"},
0x1f56: {"ὖ", "Υ̓͂", "Υ̓͂"},
0x1fb6: {"ᾶ", "Α͂", "Α͂"},
0x1fc6: {"ῆ", "Η͂", "Η͂"},
0x1fd2: {"ῒ", "Ϊ̀", "Ϊ̀"},
0x1fd3: {"ΐ", "Ϊ́", "Ϊ́"},
0x1fd6: {"ῖ", "Ι͂", "Ι͂"},
0x1fd7: {"ῗ", "Ϊ͂", "Ϊ͂"},
0x1fe2: {"ῢ", "Ϋ̀", "Ϋ̀"},
0x1fe3: {"ΰ", "Ϋ́", "Ϋ́"},
0x1fe4: {"ῤ", "Ρ̓", "Ρ̓"},
0x1fe6: {"ῦ", "Υ͂", "Υ͂"},
0x1fe7: {"ῧ", "Ϋ͂", "Ϋ͂"},
0x1ff6: {"ῶ", "Ω͂", "Ω͂"},
0x1f80: {"ᾀ", "ᾈ", "ἈΙ"},
0x1f81: {"ᾁ", "ᾉ", "ἉΙ"},
0x1f82: {"ᾂ", "ᾊ", "ἊΙ"},
0x1f83: {"ᾃ", "ᾋ", "ἋΙ"},
0x1f84: {"ᾄ", "ᾌ", "ἌΙ"},
0x1f85: {"ᾅ", "ᾍ", "ἍΙ"},
0x1f86: {"ᾆ", "ᾎ", "ἎΙ"},
0x1f87: {"ᾇ", "ᾏ", "ἏΙ"},
0x1f88: {"ᾀ", "ᾈ", "ἈΙ"},
0x1f89: {"ᾁ", "ᾉ", "ἉΙ"},
0x1f8a: {"ᾂ", "ᾊ", "ἊΙ"},
0x1f8b: {"ᾃ", "ᾋ", "ἋΙ"},
0x1f8c: {"ᾄ", "ᾌ", "ἌΙ"},
0x1f8d: {"ᾅ", "ᾍ", "ἍΙ"},
0x1f8e: {"ᾆ", "ᾎ", "ἎΙ"},
0x1f8f: {"ᾇ", "ᾏ", "ἏΙ"},
0x1f90: {"ᾐ", "ᾘ", "ἨΙ"},
0x1f91: {"ᾑ", "ᾙ", "ἩΙ"},
0x1f92: {"ᾒ", "ᾚ", "ἪΙ"},
0x1f93: {"ᾓ", "ᾛ", "ἫΙ"},
0x1f94: {"ᾔ", "ᾜ", "ἬΙ"},
0x1f95: {"ᾕ", "ᾝ", "ἭΙ"},
0x1f96: {"ᾖ", "ᾞ", "ἮΙ"},
0x1f97: {"ᾗ", "ᾟ", "ἯΙ"},
0x1f98: {"ᾐ", "ᾘ", "ἨΙ"},
0x1f99: {"ᾑ", "ᾙ", "ἩΙ"},
0x1f9a: {"ᾒ", "ᾚ", "ἪΙ"},
0x1f9b: {"ᾓ", "ᾛ", "ἫΙ"},
0x1f9c: {"ᾔ", "ᾜ", "ἬΙ"},
0x1f9d: {"ᾕ", "ᾝ", "ἭΙ"},
0x1f9e: {"ᾖ", "ᾞ", "ἮΙ"},
0x1f9f: {"ᾗ", "ᾟ", "ἯΙ"},
0x1fa0: {"ᾠ", "ᾨ", "ὨΙ"},
0x1fa1: {"ᾡ", "ᾩ", "ὩΙ"},
0x1fa2: {"ᾢ", "ᾪ", "ὪΙ"},
0x1fa3: {"ᾣ", "ᾫ", "ὫΙ"},
0x1fa4: {"ᾤ", "ᾬ", "ὬΙ"},
0x1fa5: {"ᾥ", "ᾭ", "ὭΙ"},
0x1fa6: {"ᾦ", "ᾮ", "ὮΙ"},
0x1fa7: {"ᾧ", "ᾯ", "ὯΙ"},
0x1fa8: {"ᾠ", "ᾨ", "ὨΙ"},
0x1fa9: {"ᾡ", "ᾩ", "ὩΙ"},
0x1faa: {"ᾢ", "ᾪ", "ὪΙ"},
0x1fab: {"ᾣ", "ᾫ", "ὫΙ"},
0x1fac: {"ᾤ", "ᾬ", "ὬΙ"},
0x1fad: {"ᾥ", "ᾭ", "ὭΙ"},
0x1fae: {"ᾦ", "ᾮ", "ὮΙ"},
0x1faf: {"ᾧ", "ᾯ", "ὯΙ"},
0x1fb3: {"ᾳ", "ᾼ", "ΑΙ"},
0x1fbc: {"ᾳ", "ᾼ", "ΑΙ"},
0x1fc3: {"ῃ", "ῌ", "ΗΙ"},
0x1fcc: {"ῃ", "ῌ", "ΗΙ"},
0x1ff3: {"ῳ", "ῼ", "ΩΙ"},
0x1ffc: {"ῳ", "ῼ", "ΩΙ"},
0x1fb2: {"ᾲ", "Ὰͅ", "ᾺΙ"},
0x1fb4: {"ᾴ", "Άͅ", "ΆΙ"},
0x1fc2: {"ῂ", "Ὴͅ", "ῊΙ"},
0x1fc4: {"ῄ", "Ήͅ", "ΉΙ"},
0x1ff2: {"ῲ", "Ὼͅ", "ῺΙ"},
0x1ff4: {"ῴ", "Ώͅ", "ΏΙ"},
0x1fb7: {"ᾷ", "ᾼ͂", "Α͂Ι"},
0x1fc7: {"ῇ", "ῌ͂", "Η͂Ι"},
0x1ff7: {"ῷ", "ῼ͂", "Ω͂Ι"},
}
breakProp = []struct{ lo, hi rune }{
{0x0, 0x26},
{0x28, 0x2d},
{0x2f, 0x2f},
{0x3b, 0x40},
{0x5b, 0x5e},
{0x60, 0x60},
{0x7b, 0xa9},
{0xab, 0xac},
{0xae, 0xb4},
{0xb6, 0xb6},
{0xb8, 0xb9},
{0xbb, 0xbf},
{0xd7, 0xd7},
{0xf7, 0xf7},
{0x2c2, 0x2c5},
{0x2d2, 0x2d6},
{0x2d8, 0x2df},
{0x2e5, 0x2eb},
{0x2ed, 0x2ed},
{0x2ef, 0x2ff},
{0x375, 0x375},
{0x378, 0x379},
{0x37e, 0x37e},
{0x380, 0x385},
{0x38b, 0x38b},
{0x38d, 0x38d},
{0x3a2, 0x3a2},
{0x3f6, 0x3f6},
{0x482, 0x482},
{0x530, 0x530},
{0x557, 0x558},
{0x55a, 0x560},
{0x588, 0x590},
{0x5be, 0x5be},
{0x5c0, 0x5c0},
{0x5c3, 0x5c3},
{0x5c6, 0x5c6},
{0x5c8, 0x5cf},
{0x5eb, 0x5ef},
{0x5f5, 0x5ff},
{0x606, 0x60f},
{0x61b, 0x61b},
{0x61d, 0x61f},
{0x66a, 0x66a},
{0x66c, 0x66d},
{0x6d4, 0x6d4},
{0x6de, 0x6de},
{0x6e9, 0x6e9},
{0x6fd, 0x6fe},
{0x700, 0x70e},
{0x74b, 0x74c},
{0x7b2, 0x7bf},
{0x7f6, 0x7f9},
{0x7fb, 0x7ff},
{0x82e, 0x83f},
{0x85c, 0x89f},
{0x8b5, 0x8e2},
{0x964, 0x965},
{0x970, 0x970},
{0x984, 0x984},
{0x98d, 0x98e},
{0x991, 0x992},
{0x9a9, 0x9a9},
{0x9b1, 0x9b1},
{0x9b3, 0x9b5},
{0x9ba, 0x9bb},
{0x9c5, 0x9c6},
{0x9c9, 0x9ca},
{0x9cf, 0x9d6},
{0x9d8, 0x9db},
{0x9de, 0x9de},
{0x9e4, 0x9e5},
{0x9f2, 0xa00},
{0xa04, 0xa04},
{0xa0b, 0xa0e},
{0xa11, 0xa12},
{0xa29, 0xa29},
{0xa31, 0xa31},
{0xa34, 0xa34},
{0xa37, 0xa37},
{0xa3a, 0xa3b},
{0xa3d, 0xa3d},
{0xa43, 0xa46},
{0xa49, 0xa4a},
{0xa4e, 0xa50},
{0xa52, 0xa58},
{0xa5d, 0xa5d},
{0xa5f, 0xa65},
{0xa76, 0xa80},
{0xa84, 0xa84},
{0xa8e, 0xa8e},
{0xa92, 0xa92},
{0xaa9, 0xaa9},
{0xab1, 0xab1},
{0xab4, 0xab4},
{0xaba, 0xabb},
{0xac6, 0xac6},
{0xaca, 0xaca},
{0xace, 0xacf},
{0xad1, 0xadf},
{0xae4, 0xae5},
{0xaf0, 0xaf8},
{0xafa, 0xb00},
{0xb04, 0xb04},
{0xb0d, 0xb0e},
{0xb11, 0xb12},
{0xb29, 0xb29},
{0xb31, 0xb31},
{0xb34, 0xb34},
{0xb3a, 0xb3b},
{0xb45, 0xb46},
{0xb49, 0xb4a},
{0xb4e, 0xb55},
{0xb58, 0xb5b},
{0xb5e, 0xb5e},
{0xb64, 0xb65},
{0xb70, 0xb70},
{0xb72, 0xb81},
{0xb84, 0xb84},
{0xb8b, 0xb8d},
{0xb91, 0xb91},
{0xb96, 0xb98},
{0xb9b, 0xb9b},
{0xb9d, 0xb9d},
{0xba0, 0xba2},
{0xba5, 0xba7},
{0xbab, 0xbad},
{0xbba, 0xbbd},
{0xbc3, 0xbc5},
{0xbc9, 0xbc9},
{0xbce, 0xbcf},
{0xbd1, 0xbd6},
{0xbd8, 0xbe5},
{0xbf0, 0xbff},
{0xc04, 0xc04},
{0xc0d, 0xc0d},
{0xc11, 0xc11},
{0xc29, 0xc29},
{0xc3a, 0xc3c},
{0xc45, 0xc45},
{0xc49, 0xc49},
{0xc4e, 0xc54},
{0xc57, 0xc57},
{0xc5b, 0xc5f},
{0xc64, 0xc65},
{0xc70, 0xc80},
{0xc84, 0xc84},
{0xc8d, 0xc8d},
{0xc91, 0xc91},
{0xca9, 0xca9},
{0xcb4, 0xcb4},
{0xcba, 0xcbb},
{0xcc5, 0xcc5},
{0xcc9, 0xcc9},
{0xcce, 0xcd4},
{0xcd7, 0xcdd},
{0xcdf, 0xcdf},
{0xce4, 0xce5},
{0xcf0, 0xcf0},
{0xcf3, 0xd00},
{0xd04, 0xd04},
{0xd0d, 0xd0d},
{0xd11, 0xd11},
{0xd3b, 0xd3c},
{0xd45, 0xd45},
{0xd49, 0xd49},
{0xd4f, 0xd56},
{0xd58, 0xd5e},
{0xd64, 0xd65},
{0xd70, 0xd79},
{0xd80, 0xd81},
{0xd84, 0xd84},
{0xd97, 0xd99},
{0xdb2, 0xdb2},
{0xdbc, 0xdbc},
{0xdbe, 0xdbf},
{0xdc7, 0xdc9},
{0xdcb, 0xdce},
{0xdd5, 0xdd5},
{0xdd7, 0xdd7},
{0xde0, 0xde5},
{0xdf0, 0xdf1},
{0xdf4, 0xe30},
{0xe32, 0xe33},
{0xe3b, 0xe46},
{0xe4f, 0xe4f},
{0xe5a, 0xeb0},
{0xeb2, 0xeb3},
{0xeba, 0xeba},
{0xebd, 0xec7},
{0xece, 0xecf},
{0xeda, 0xeff},
{0xf01, 0xf17},
{0xf1a, 0xf1f},
{0xf2a, 0xf34},
{0xf36, 0xf36},
{0xf38, 0xf38},
{0xf3a, 0xf3d},
{0xf48, 0xf48},
{0xf6d, 0xf70},
{0xf85, 0xf85},
{0xf98, 0xf98},
{0xfbd, 0xfc5},
{0xfc7, 0x102a},
{0x103f, 0x103f},
{0x104a, 0x1055},
{0x105a, 0x105d},
{0x1061, 0x1061},
{0x1065, 0x1066},
{0x106e, 0x1070},
{0x1075, 0x1081},
{0x108e, 0x108e},
{0x109e, 0x109f},
{0x10c6, 0x10c6},
{0x10c8, 0x10cc},
{0x10ce, 0x10cf},
{0x10fb, 0x10fb},
{0x1249, 0x1249},
{0x124e, 0x124f},
{0x1257, 0x1257},
{0x1259, 0x1259},
{0x125e, 0x125f},
{0x1289, 0x1289},
{0x128e, 0x128f},
{0x12b1, 0x12b1},
{0x12b6, 0x12b7},
{0x12bf, 0x12bf},
{0x12c1, 0x12c1},
{0x12c6, 0x12c7},
{0x12d7, 0x12d7},
{0x1311, 0x1311},
{0x1316, 0x1317},
{0x135b, 0x135c},
{0x1360, 0x137f},
{0x1390, 0x139f},
{0x13f6, 0x13f7},
{0x13fe, 0x1400},
{0x166d, 0x166e},
{0x1680, 0x1680},
{0x169b, 0x169f},
{0x16eb, 0x16ed},
{0x16f9, 0x16ff},
{0x170d, 0x170d},
{0x1715, 0x171f},
{0x1735, 0x173f},
{0x1754, 0x175f},
{0x176d, 0x176d},
{0x1771, 0x1771},
{0x1774, 0x17b3},
{0x17d4, 0x17dc},
{0x17de, 0x17df},
{0x17ea, 0x180a},
{0x180f, 0x180f},
{0x181a, 0x181f},
{0x1878, 0x187f},
{0x18ab, 0x18af},
{0x18f6, 0x18ff},
{0x191f, 0x191f},
{0x192c, 0x192f},
{0x193c, 0x1945},
{0x1950, 0x19cf},
{0x19da, 0x19ff},
{0x1a1c, 0x1a54},
{0x1a5f, 0x1a5f},
{0x1a7d, 0x1a7e},
{0x1a8a, 0x1a8f},
{0x1a9a, 0x1aaf},
{0x1abf, 0x1aff},
{0x1b4c, 0x1b4f},
{0x1b5a, 0x1b6a},
{0x1b74, 0x1b7f},
{0x1bf4, 0x1bff},
{0x1c38, 0x1c3f},
{0x1c4a, 0x1c4c},
{0x1c7e, 0x1ccf},
{0x1cd3, 0x1cd3},
{0x1cf7, 0x1cf7},
{0x1cfa, 0x1cff},
{0x1df6, 0x1dfb},
{0x1f16, 0x1f17},
{0x1f1e, 0x1f1f},
{0x1f46, 0x1f47},
{0x1f4e, 0x1f4f},
{0x1f58, 0x1f58},
{0x1f5a, 0x1f5a},
{0x1f5c, 0x1f5c},
{0x1f5e, 0x1f5e},
{0x1f7e, 0x1f7f},
{0x1fb5, 0x1fb5},
{0x1fbd, 0x1fbd},
{0x1fbf, 0x1fc1},
{0x1fc5, 0x1fc5},
{0x1fcd, 0x1fcf},
{0x1fd4, 0x1fd5},
{0x1fdc, 0x1fdf},
{0x1fed, 0x1ff1},
{0x1ff5, 0x1ff5},
{0x1ffd, 0x200b},
{0x2010, 0x2017},
{0x201a, 0x2023},
{0x2025, 0x2026},
{0x2028, 0x2029},
{0x202f, 0x203e},
{0x2041, 0x2053},
{0x2055, 0x205f},
{0x2065, 0x2065},
{0x2070, 0x2070},
{0x2072, 0x207e},
{0x2080, 0x208f},
{0x209d, 0x20cf},
{0x20f1, 0x2101},
{0x2103, 0x2106},
{0x2108, 0x2109},
{0x2114, 0x2114},
{0x2116, 0x2118},
{0x211e, 0x2123},
{0x2125, 0x2125},
{0x2127, 0x2127},
{0x2129, 0x2129},
{0x212e, 0x212e},
{0x213a, 0x213b},
{0x2140, 0x2144},
{0x214a, 0x214d},
{0x214f, 0x215f},
{0x2189, 0x24b5},
{0x24ea, 0x2bff},
{0x2c2f, 0x2c2f},
{0x2c5f, 0x2c5f},
{0x2ce5, 0x2cea},
{0x2cf4, 0x2cff},
{0x2d26, 0x2d26},
{0x2d28, 0x2d2c},
{0x2d2e, 0x2d2f},
{0x2d68, 0x2d6e},
{0x2d70, 0x2d7e},
{0x2d97, 0x2d9f},
{0x2da7, 0x2da7},
{0x2daf, 0x2daf},
{0x2db7, 0x2db7},
{0x2dbf, 0x2dbf},
{0x2dc7, 0x2dc7},
{0x2dcf, 0x2dcf},
{0x2dd7, 0x2dd7},
{0x2ddf, 0x2ddf},
{0x2e00, 0x2e2e},
{0x2e30, 0x3004},
{0x3006, 0x3029},
{0x3030, 0x303a},
{0x303d, 0x3098},
{0x309b, 0x3104},
{0x312e, 0x3130},
{0x318f, 0x319f},
{0x31bb, 0x9fff},
{0xa48d, 0xa4cf},
{0xa4fe, 0xa4ff},
{0xa60d, 0xa60f},
{0xa62c, 0xa63f},
{0xa673, 0xa673},
{0xa67e, 0xa67e},
{0xa6f2, 0xa716},
{0xa720, 0xa721},
{0xa789, 0xa78a},
{0xa7ae, 0xa7af},
{0xa7b8, 0xa7f6},
{0xa828, 0xa83f},
{0xa874, 0xa87f},
{0xa8c5, 0xa8cf},
{0xa8da, 0xa8df},
{0xa8f8, 0xa8fa},
{0xa8fc, 0xa8fc},
{0xa8fe, 0xa8ff},
{0xa92e, 0xa92f},
{0xa954, 0xa95f},
{0xa97d, 0xa97f},
{0xa9c1, 0xa9ce},
{0xa9da, 0xa9e4},
{0xa9e6, 0xa9ef},
{0xa9fa, 0xa9ff},
{0xaa37, 0xaa3f},
{0xaa4e, 0xaa4f},
{0xaa5a, 0xaa7a},
{0xaa7e, 0xaaaf},
{0xaab1, 0xaab1},
{0xaab5, 0xaab6},
{0xaab9, 0xaabd},
{0xaac0, 0xaac0},
{0xaac2, 0xaadf},
{0xaaf0, 0xaaf1},
{0xaaf7, 0xab00},
{0xab07, 0xab08},
{0xab0f, 0xab10},
{0xab17, 0xab1f},
{0xab27, 0xab27},
{0xab2f, 0xab2f},
{0xab5b, 0xab5b},
{0xab66, 0xab6f},
{0xabeb, 0xabeb},
{0xabee, 0xabef},
{0xabfa, 0xabff},
{0xd7a4, 0xd7af},
{0xd7c7, 0xd7ca},
{0xd7fc, 0xfaff},
{0xfb07, 0xfb12},
{0xfb18, 0xfb1c},
{0xfb29, 0xfb29},
{0xfb37, 0xfb37},
{0xfb3d, 0xfb3d},
{0xfb3f, 0xfb3f},
{0xfb42, 0xfb42},
{0xfb45, 0xfb45},
{0xfbb2, 0xfbd2},
{0xfd3e, 0xfd4f},
{0xfd90, 0xfd91},
{0xfdc8, 0xfdef},
{0xfdfc, 0xfdff},
{0xfe10, 0xfe12},
{0xfe14, 0xfe1f},
{0xfe30, 0xfe32},
{0xfe35, 0xfe4c},
{0xfe50, 0xfe51},
{0xfe53, 0xfe54},
{0xfe56, 0xfe6f},
{0xfe75, 0xfe75},
{0xfefd, 0xfefe},
{0xff00, 0xff06},
{0xff08, 0xff0d},
{0xff0f, 0xff19},
{0xff1b, 0xff20},
{0xff3b, 0xff3e},
{0xff40, 0xff40},
{0xff5b, 0xff9d},
{0xffbf, 0xffc1},
{0xffc8, 0xffc9},
{0xffd0, 0xffd1},
{0xffd8, 0xffd9},
{0xffdd, 0xfff8},
{0xfffc, 0xffff},
{0x1000c, 0x1000c},
{0x10027, 0x10027},
{0x1003b, 0x1003b},
{0x1003e, 0x1003e},
{0x1004e, 0x1004f},
{0x1005e, 0x1007f},
{0x100fb, 0x1013f},
{0x10175, 0x101fc},
{0x101fe, 0x1027f},
{0x1029d, 0x1029f},
{0x102d1, 0x102df},
{0x102e1, 0x102ff},
{0x10320, 0x1032f},
{0x1034b, 0x1034f},
{0x1037b, 0x1037f},
{0x1039e, 0x1039f},
{0x103c4, 0x103c7},
{0x103d0, 0x103d0},
{0x103d6, 0x103ff},
{0x1049e, 0x1049f},
{0x104aa, 0x104ff},
{0x10528, 0x1052f},
{0x10564, 0x105ff},
{0x10737, 0x1073f},
{0x10756, 0x1075f},
{0x10768, 0x107ff},
{0x10806, 0x10807},
{0x10809, 0x10809},
{0x10836, 0x10836},
{0x10839, 0x1083b},
{0x1083d, 0x1083e},
{0x10856, 0x1085f},
{0x10877, 0x1087f},
{0x1089f, 0x108df},
{0x108f3, 0x108f3},
{0x108f6, 0x108ff},
{0x10916, 0x1091f},
{0x1093a, 0x1097f},
{0x109b8, 0x109bd},
{0x109c0, 0x109ff},
{0x10a04, 0x10a04},
{0x10a07, 0x10a0b},
{0x10a14, 0x10a14},
{0x10a18, 0x10a18},
{0x10a34, 0x10a37},
{0x10a3b, 0x10a3e},
{0x10a40, 0x10a5f},
{0x10a7d, 0x10a7f},
{0x10a9d, 0x10abf},
{0x10ac8, 0x10ac8},
{0x10ae7, 0x10aff},
{0x10b36, 0x10b3f},
{0x10b56, 0x10b5f},
{0x10b73, 0x10b7f},
{0x10b92, 0x10bff},
{0x10c49, 0x10c7f},
{0x10cb3, 0x10cbf},
{0x10cf3, 0x10fff},
{0x11047, 0x11065},
{0x11070, 0x1107e},
{0x110bb, 0x110bc},
{0x110be, 0x110cf},
{0x110e9, 0x110ef},
{0x110fa, 0x110ff},
{0x11135, 0x11135},
{0x11140, 0x1114f},
{0x11174, 0x11175},
{0x11177, 0x1117f},
{0x111c5, 0x111c9},
{0x111cd, 0x111cf},
{0x111db, 0x111db},
{0x111dd, 0x111ff},
{0x11212, 0x11212},
{0x11238, 0x1127f},
{0x11287, 0x11287},
{0x11289, 0x11289},
{0x1128e, 0x1128e},
{0x1129e, 0x1129e},
{0x112a9, 0x112af},
{0x112eb, 0x112ef},
{0x112fa, 0x112ff},
{0x11304, 0x11304},
{0x1130d, 0x1130e},
{0x11311, 0x11312},
{0x11329, 0x11329},
{0x11331, 0x11331},
{0x11334, 0x11334},
{0x1133a, 0x1133b},
{0x11345, 0x11346},
{0x11349, 0x1134a},
{0x1134e, 0x1134f},
{0x11351, 0x11356},
{0x11358, 0x1135c},
{0x11364, 0x11365},
{0x1136d, 0x1136f},
{0x11375, 0x1147f},
{0x114c6, 0x114c6},
{0x114c8, 0x114cf},
{0x114da, 0x1157f},
{0x115b6, 0x115b7},
{0x115c1, 0x115d7},
{0x115de, 0x115ff},
{0x11641, 0x11643},
{0x11645, 0x1164f},
{0x1165a, 0x1167f},
{0x116b8, 0x116bf},
{0x116ca, 0x1171c},
{0x1172c, 0x1172f},
{0x1173a, 0x1189f},
{0x118ea, 0x118fe},
{0x11900, 0x11abf},
{0x11af9, 0x11fff},
{0x1239a, 0x123ff},
{0x1246f, 0x1247f},
{0x12544, 0x12fff},
{0x1342f, 0x143ff},
{0x14647, 0x167ff},
{0x16a39, 0x16a3f},
{0x16a5f, 0x16a5f},
{0x16a6a, 0x16acf},
{0x16aee, 0x16aef},
{0x16af5, 0x16aff},
{0x16b37, 0x16b3f},
{0x16b44, 0x16b4f},
{0x16b5a, 0x16b62},
{0x16b78, 0x16b7c},
{0x16b90, 0x16eff},
{0x16f45, 0x16f4f},
{0x16f7f, 0x16f8e},
{0x16fa0, 0x1bbff},
{0x1bc6b, 0x1bc6f},
{0x1bc7d, 0x1bc7f},
{0x1bc89, 0x1bc8f},
{0x1bc9a, 0x1bc9c},
{0x1bc9f, 0x1bc9f},
{0x1bca4, 0x1d164},
{0x1d16a, 0x1d16c},
{0x1d183, 0x1d184},
{0x1d18c, 0x1d1a9},
{0x1d1ae, 0x1d241},
{0x1d245, 0x1d3ff},
{0x1d455, 0x1d455},
{0x1d49d, 0x1d49d},
{0x1d4a0, 0x1d4a1},
{0x1d4a3, 0x1d4a4},
{0x1d4a7, 0x1d4a8},
{0x1d4ad, 0x1d4ad},
{0x1d4ba, 0x1d4ba},
{0x1d4bc, 0x1d4bc},
{0x1d4c4, 0x1d4c4},
{0x1d506, 0x1d506},
{0x1d50b, 0x1d50c},
{0x1d515, 0x1d515},
{0x1d51d, 0x1d51d},
{0x1d53a, 0x1d53a},
{0x1d53f, 0x1d53f},
{0x1d545, 0x1d545},
{0x1d547, 0x1d549},
{0x1d551, 0x1d551},
{0x1d6a6, 0x1d6a7},
{0x1d6c1, 0x1d6c1},
{0x1d6db, 0x1d6db},
{0x1d6fb, 0x1d6fb},
{0x1d715, 0x1d715},
{0x1d735, 0x1d735},
{0x1d74f, 0x1d74f},
{0x1d76f, 0x1d76f},
{0x1d789, 0x1d789},
{0x1d7a9, 0x1d7a9},
{0x1d7c3, 0x1d7c3},
{0x1d7cc, 0x1d7cd},
{0x1d800, 0x1d9ff},
{0x1da37, 0x1da3a},
{0x1da6d, 0x1da74},
{0x1da76, 0x1da83},
{0x1da85, 0x1da9a},
{0x1daa0, 0x1daa0},
{0x1dab0, 0x1e7ff},
{0x1e8c5, 0x1e8cf},
{0x1e8d7, 0x1edff},
{0x1ee04, 0x1ee04},
{0x1ee20, 0x1ee20},
{0x1ee23, 0x1ee23},
{0x1ee25, 0x1ee26},
{0x1ee28, 0x1ee28},
{0x1ee33, 0x1ee33},
{0x1ee38, 0x1ee38},
{0x1ee3a, 0x1ee3a},
{0x1ee3c, 0x1ee41},
{0x1ee43, 0x1ee46},
{0x1ee48, 0x1ee48},
{0x1ee4a, 0x1ee4a},
{0x1ee4c, 0x1ee4c},
{0x1ee50, 0x1ee50},
{0x1ee53, 0x1ee53},
{0x1ee55, 0x1ee56},
{0x1ee58, 0x1ee58},
{0x1ee5a, 0x1ee5a},
{0x1ee5c, 0x1ee5c},
{0x1ee5e, 0x1ee5e},
{0x1ee60, 0x1ee60},
{0x1ee63, 0x1ee63},
{0x1ee65, 0x1ee66},
{0x1ee6b, 0x1ee6b},
{0x1ee73, 0x1ee73},
{0x1ee78, 0x1ee78},
{0x1ee7d, 0x1ee7d},
{0x1ee7f, 0x1ee7f},
{0x1ee8a, 0x1ee8a},
{0x1ee9c, 0x1eea0},
{0x1eea4, 0x1eea4},
{0x1eeaa, 0x1eeaa},
{0x1eebc, 0x1f12f},
{0x1f14a, 0x1f14f},
{0x1f16a, 0x1f16f},
{0x1f18a, 0x1ffff},
}
breakTest = []string{
"AA",
"ÄA",
"Aa\u2060",
"Äa\u2060",
"Aa|:",
"Äa|:",
"Aa|'",
"Äa|'",
"Aa|'\u2060",
"Äa|'\u2060",
"Aa|,",
"Äa|,",
"a\u2060A",
"a\u2060̈A",
"a\u2060a\u2060",
"a\u2060̈a\u2060",
"a\u2060a|:",
"a\u2060̈a|:",
"a\u2060a|'",
"a\u2060̈a|'",
"a\u2060a|'\u2060",
"a\u2060̈a|'\u2060",
"a\u2060a|,",
"a\u2060̈a|,",
"a:A",
"a:̈A",
"a:a\u2060",
"a:̈a\u2060",
"a:a|:",
"a:̈a|:",
"a:a|'",
"a:̈a|'",
"a:a|'\u2060",
"a:̈a|'\u2060",
"a:a|,",
"a:̈a|,",
"a'A",
"a'̈A",
"a'a\u2060",
"a'̈a\u2060",
"a'a|:",
"a'̈a|:",
"a'a|'",
"a'̈a|'",
"a'a|'\u2060",
"a'̈a|'\u2060",
"a'a|,",
"a'̈a|,",
"a'\u2060A",
"a'\u2060̈A",
"a'\u2060a\u2060",
"a'\u2060̈a\u2060",
"a'\u2060a|:",
"a'\u2060̈a|:",
"a'\u2060a|'",
"a'\u2060̈a|'",
"a'\u2060a|'\u2060",
"a'\u2060̈a|'\u2060",
"a'\u2060a|,",
"a'\u2060̈a|,",
"a|,|A",
"a|,̈|A",
"a|,|a\u2060",
"a|,̈|a\u2060",
"a|,|a|:",
"a|,̈|a|:",
"a|,|a|'",
"a|,̈|a|'",
"a|,|a|'\u2060",
"a|,̈|a|'\u2060",
"a|,|a|,",
"a|,̈|a|,",
"can't",
"can’t",
"ab\u00adby",
"a|$|-|34,567.14|%|b",
"c.d",
"C.d",
"c.D",
"C.D",
"\u2060|c\u2060a\u2060n\u2060'\u2060t\u2060\u2060",
"\u2060|c\u2060a\u2060n\u2060\u2060t\u2060\u2060",
"\u2060|a\u2060b\u2060\u00ad\u2060b\u2060y\u2060\u2060",
"\u2060|a\u2060|$\u2060|-\u2060|3\u20604\u2060,\u20605\u20606\u20607\u2060.\u20601\u20604\u2060|%\u2060|b\u2060\u2060",
"\u2060|c\u2060.\u2060d\u2060\u2060",
"\u2060|C\u2060.\u2060d\u2060\u2060",
"\u2060|c\u2060.\u2060D\u2060\u2060",
"\u2060|C\u2060.\u2060D\u2060\u2060",
"a|🇦|b",
"1_a|:|:|a",
"1_a|:|.|a",
"1_a|:|,|a",
"1_a|.|:|a",
"1_a|.|.|a",
"1_a|.|,|a",
"1_a|,|:|a",
"1_a|,|.|a",
"1_a|,|,|a",
"a_a|:|:|1",
"a|:|:|a",
"a_1|:|:|a",
"a_a|:|:|a",
"a_a|:|.|1",
"a|:|.|a",
"a_1|:|.|a",
"a_a|:|.|a",
"a_a|:|,|1",
"a|:|,|a",
"a_1|:|,|a",
"a_a|:|,|a",
"a_a|.|:|1",
"a|.|:|a",
"a_1|.|:|a",
"a_a|.|:|a",
"a_a|.|.|1",
"a|.|.|a",
"a_1|.|.|a",
"a_a|.|.|a",
"a_a|.|,|1",
"a|.|,|a",
"a_1|.|,|a",
"a_a|.|,|a",
"a_a|,|:|1",
"a|,|:|a",
"a_1|,|:|a",
"a_a|,|:|a",
"a_a|,|.|1",
"a|,|.|a",
"a_1|,|.|a",
"a_a|,|.|a",
"a_a|,|,|1",
"a|,|,|a",
"a_1|,|,|a",
"a_a|,|,|a",
}
)
// This file was generated by go generate; DO NOT EDIT
package cases
// This file contains definitions for interpreting the trie value of the case
// trie generated by "go run gen*.go". It is shared by both the generator
// program and the resultant package. Sharing is achieved by the generator
// copying gen_trieval.go to trieval.go and changing what's above this comment.
// info holds case information for a single rune. It is the value returned
// by a trie lookup. Most mapping information can be stored in a single 16-bit
// value. If not, for example when a rune is mapped to multiple runes, the value
// stores some basic case data and an index into an array with additional data.
//
// The per-rune values have the following format:
//
// if (exception) {
// 15..5 unsigned exception index
// 4 unused
// } else {
// 15..7 XOR pattern or index to XOR pattern for case mapping
// 6 index: interpret the XOR pattern as an index
// 5..4 CCC: zero (normal or break), above or other
// }
// 3 exception: interpret this value as an exception index
// 2..0 case mode
//
// For the non-exceptional cases, a rune must be either uncased, lowercase or
// uppercase. If the rune is cased, the XOR pattern maps either a lowercase
// rune to uppercase or an uppercase rune to lowercase (applied to the 10
// least-significant bits of the rune).
//
// See the definitions below for a more detailed description of the various
// bits.
type info uint16
const (
casedMask = 0x0003
fullCasedMask = 0x0007
ignorableMask = 0x0006
ignorableValue = 0x0004
exceptionBit = 1 << 3
exceptionShift = 5
numExceptionBits = 11
xorIndexBit = 1 << 6
xorShift = 7
// There is no mapping if all xor bits and the exception bit are zero.
hasMappingMask = 0xffc0 | exceptionBit
)
// The case mode bits encodes the case type of a rune. This includes uncased,
// title, upper and lower case and case ignorable. (For a definition of these
// terms see Chapter 3 of The Unicode Standard Core Specification.) In some rare
// cases, a rune can be both cased and case-ignorable. This is encoded by
// cIgnorableCased. A rune of this type is always lower case. Some runes are
// cased while not having a mapping.
//
// A common pattern for scripts in the Unicode standard is for upper and lower
// case runes to alternate for increasing rune values (e.g. the accented Latin
// ranges starting from U+0100 and U+1E00 among others andsome Cyrillic
// characters). We use this property by defining a cXORCase mode, where the case
// mode (always upper or lower case) is derived from the rune value. As the XOR
// pattern for case mappings is often identical for successive runes, using
// cXORCase can result in large series of identical trie values. This, in turn,
// allows us to better compress the trie blocks.
const (
cUncased info = iota // 000
cTitle // 001
cLower // 010
cUpper // 011
cIgnorableUncased // 100
cIgnorableCased // 101 // lower case if mappings exist
cXORCase // 11x // case is cLower | ((rune&1) ^ x)
maxCaseMode = cUpper
)
func (c info) isCased() bool {
return c&casedMask != 0
}
func (c info) isCaseIgnorable() bool {
return c&ignorableMask == ignorableValue
}
func (c info) isCaseIgnorableAndNonBreakStarter() bool {
return c&(fullCasedMask|cccMask) == (ignorableValue | cccZero)
}
func (c info) isNotCasedAndNotCaseIgnorable() bool {
return c&fullCasedMask == 0
}
func (c info) isCaseIgnorableAndNotCased() bool {
return c&fullCasedMask == cIgnorableUncased
}
// The case mapping implementation will need to know about various Canonical
// Combining Class (CCC) values. We encode two of these in the trie value:
// cccZero (0) and cccAbove (230). If the value is cccOther, it means that
// CCC(r) > 0, but not 230. A value of cccBreak means that CCC(r) == 0 and that
// the rune also has the break category Break (see below).
const (
cccBreak info = iota << 4
cccZero
cccAbove
cccOther
cccMask = cccBreak | cccZero | cccAbove | cccOther
)
func (c info) cccVal() info {
if c&exceptionBit != 0 {
return cccZero
}
return c & cccMask
}
func (c info) cccType() info {
ccc := c.cccVal()
if ccc <= cccZero {
return cccZero
}
return ccc
}
const (
starter = 0
above = 230
iotaSubscript = 240
)
// TODO: Implement full Unicode breaking algorithm:
// 1) Implement breaking in separate package.
// 2) Use the breaker here.
// 3) Compare table size and performance of using the more generic breaker.
//
// Note that we can extend the current algorithm to be much more accurate. This
// only makes sense, though, if the performance and/or space penalty of using
// the generic breaker is big. Extra data will only be needed for non-cased
// runes, which means there are sufficient bits left in the caseType.
// Also note that the standard breaking algorithm doesn't always make sense
// for title casing. For example, a4a -> A4a, but a"4a -> A"4A (where " stands
// for modifier \u0308).
// ICU prohibits breaking in such cases as well.
// For the purpose of title casing we use an approximation of the Unicode Word
// Breaking algorithm defined in Annex #29:
// http://www.unicode.org/reports/tr29/#Default_Grapheme_Cluster_Table.
//
// For our approximation, we group the Word Break types into the following
// categories, with associated rules:
//
// 1) Letter:
// ALetter, Hebrew_Letter, Numeric, ExtendNumLet, Extend.
// Rule: Never break between consecutive runes of this category.
//
// 2) Mid:
// Format, MidLetter, MidNumLet, Single_Quote.
// (Cf. case-ignorable: MidLetter, MidNumLet or cat is Mn, Me, Cf, Lm or Sk).
// Rule: Don't break between Letter and Mid, but break between two Mids.
//
// 3) Break:
// Any other category, including NewLine, CR, LF and Double_Quote. These
// categories should always result in a break between two cased letters.
// Rule: Always break.
//
// Note 1: the Katakana and MidNum categories can, in esoteric cases, result in
// preventing a break between two cased letters. For now we will ignore this
// (e.g. [ALetter] [ExtendNumLet] [Katakana] [ExtendNumLet] [ALetter] and
// [ALetter] [Numeric] [MidNum] [Numeric] [ALetter].)
//
// Note 2: the rule for Mid is very approximate, but works in most cases. To
// improve, we could store the categories in the trie value and use a FA to
// manage breaks. See TODO comment above.
//
// Note 3: according to the spec, it is possible for the Extend category to
// introduce breaks between other categories grouped in Letter. However, this
// is undesirable for our purposes. ICU prevents breaks in such cases as well.
// isBreak returns whether this rune should introduce a break.
func (c info) isBreak() bool {
return c.cccVal() == cccBreak
}
// isLetter returns whether the rune is of break type ALetter, Hebrew_Letter,
// Numeric, ExtendNumLet, or Extend.
func (c info) isLetter() bool {
ccc := c.cccVal()
if ccc == cccZero {
return !c.isCaseIgnorable()
}
return ccc != cccBreak
}
// The exceptions slice holds data that does not fit in a normal info entry.
// The entry is pointed to by the exception index in an entry. It has the
// following format:
//
// Header:
// byte 0: // TODO: case folding not implemented yet.
// 7 conditional case folding
// 6 conditional special casing
// 6..3 length of case folding
// 2..0 length of closure mapping (up to 7).
//
// byte 1:
// 7..6 unused
// 5..3 length of 1st mapping of case type
// 2..0 length of 2nd mapping of case type
//
// case 1st 2nd
// lower -> upper, title
// upper -> lower, title
// title -> lower, upper
//
// Lengths with the value 0x7 indicate no value and implies no change.
// A length of 0 indicates a mapping to zero-length string.
//
// Body bytes:
// lowercase mapping bytes
// uppercase mapping bytes
// titlecase mapping bytes
// case folding bytes
// closure mapping bytes
//
// Fallbacks:
// missing fold -> lower
// missing title -> upper
// all missing -> original rune
//
// exceptions starts with a dummy byte to enforce that there is no zero index
// value.
const (
lengthMask = 0x07
lengthBits = 3
noChange = 0
)
// References to generated trie.
var trie = newCaseTrie(0)
var sparse = sparseBlocks{
values: sparseValues[:],
offsets: sparseOffsets[:],
}
// Sparse block lookup code.
// valueRange is an entry in a sparse block.
type valueRange struct {
value uint16
lo, hi byte
}
type sparseBlocks struct {
values []valueRange
offsets []uint16
}
// lookup returns the value from values block n for byte b using binary search.
func (s *sparseBlocks) lookup(n uint32, b byte) uint16 {
lo := s.offsets[n]
hi := s.offsets[n+1]
for lo < hi {
m := lo + (hi-lo)/2
r := s.values[m]
if r.lo <= b && b <= r.hi {
return r.value
}
if b < r.lo {
hi = m
} else {
lo = m + 1
}
}
return 0
}
// lastRuneForTesting is the last rune used for testing. Everything after this
// is boring.
const lastRuneForTesting = rune(0x1FFFF)
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package cldr provides a parser for LDML and related XML formats.
// This package is inteded to be used by the table generation tools
// for the various internationalization-related packages.
// As the XML types are generated from the CLDR DTD, and as the CLDR standard
// is periodically amended, this package may change considerably over time.
// This mostly means that data may appear and disappear between versions.
// That is, old code should keep compiling for newer versions, but data
// may have moved or changed.
// CLDR version 22 is the first version supported by this package.
// Older versions may not work.
package cldr
import (
"encoding/xml"
"regexp"
"strconv"
)
// Elem is implemented by every XML element.
type Elem interface {
setEnclosing(Elem)
setName(string)
enclosing() Elem
GetCommon() *Common
}
type hidden struct {
CharData string `xml:",chardata"`
Alias *struct {
Common
Source string `xml:"source,attr"`
Path string `xml:"path,attr"`
} `xml:"alias"`
Def *struct {
Common
Choice string `xml:"choice,attr,omitempty"`
Type string `xml:"type,attr,omitempty"`
} `xml:"default"`
}
// Common holds several of the most common attributes and sub elements
// of an XML element.
type Common struct {
XMLName xml.Name
name string
enclElem Elem
Type string `xml:"type,attr,omitempty"`
Reference string `xml:"reference,attr,omitempty"`
Alt string `xml:"alt,attr,omitempty"`
ValidSubLocales string `xml:"validSubLocales,attr,omitempty"`
Draft string `xml:"draft,attr,omitempty"`
hidden
}
// Default returns the default type to select from the enclosed list
// or "" if no default value is specified.
func (e *Common) Default() string {
if e.Def == nil {
return ""
}
if e.Def.Choice != "" {
return e.Def.Choice
} else if e.Def.Type != "" {
// Type is still used by the default element in collation.
return e.Def.Type
}
return ""
}
// GetCommon returns e. It is provided such that Common implements Elem.
func (e *Common) GetCommon() *Common {
return e
}
// Data returns the character data accumulated for this element.
func (e *Common) Data() string {
e.CharData = charRe.ReplaceAllStringFunc(e.CharData, replaceUnicode)
return e.CharData
}
func (e *Common) setName(s string) {
e.name = s
}
func (e *Common) enclosing() Elem {
return e.enclElem
}
func (e *Common) setEnclosing(en Elem) {
e.enclElem = en
}
// Escape characters that can be escaped without further escaping the string.
var charRe = regexp.MustCompile(`&#x[0-9a-fA-F]*;|\\u[0-9a-fA-F]{4}|\\U[0-9a-fA-F]{8}|\\x[0-9a-fA-F]{2}|\\[0-7]{3}|\\[abtnvfr]`)
// replaceUnicode converts hexadecimal Unicode codepoint notations to a one-rune string.
// It assumes the input string is correctly formatted.
func replaceUnicode(s string) string {
if s[1] == '#' {
r, _ := strconv.ParseInt(s[3:len(s)-1], 16, 32)
return string(r)
}
r, _, _, _ := strconv.UnquoteChar(s, 0)
return string(r)
}
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:generate go run makexml.go -output xml.go
// Package cldr provides a parser for LDML and related XML formats.
// This package is inteded to be used by the table generation tools
// for the various internationalization-related packages.
// As the XML types are generated from the CLDR DTD, and as the CLDR standard
// is periodically amended, this package may change considerably over time.
// This mostly means that data may appear and disappear between versions.
// That is, old code should keep compiling for newer versions, but data
// may have moved or changed.
// CLDR version 22 is the first version supported by this package.
// Older versions may not work.
package cldr
import (
"fmt"
"sort"
)
// CLDR provides access to parsed data of the Unicode Common Locale Data Repository.
type CLDR struct {
parent map[string][]string
locale map[string]*LDML
resolved map[string]*LDML
bcp47 *LDMLBCP47
supp *SupplementalData
}
func makeCLDR() *CLDR {
return &CLDR{
parent: make(map[string][]string),
locale: make(map[string]*LDML),
resolved: make(map[string]*LDML),
bcp47: &LDMLBCP47{},
supp: &SupplementalData{},
}
}
// BCP47 returns the parsed BCP47 LDML data. If no such data was parsed, nil is returned.
func (cldr *CLDR) BCP47() *LDMLBCP47 {
return nil
}
// Draft indicates the draft level of an element.
type Draft int
const (
Approved Draft = iota
Contributed
Provisional
Unconfirmed
)
var drafts = []string{"unconfirmed", "provisional", "contributed", "approved", ""}
// ParseDraft returns the Draft value corresponding to the given string. The
// empty string corresponds to Approved.
func ParseDraft(level string) (Draft, error) {
if level == "" {
return Approved, nil
}
for i, s := range drafts {
if level == s {
return Unconfirmed - Draft(i), nil
}
}
return Approved, fmt.Errorf("cldr: unknown draft level %q", level)
}
func (d Draft) String() string {
return drafts[len(drafts)-1-int(d)]
}
// SetDraftLevel sets which draft levels to include in the evaluated LDML.
// Any draft element for which the draft level is higher than lev will be excluded.
// If multiple draft levels are available for a single element, the one with the
// lowest draft level will be selected, unless preferDraft is true, in which case
// the highest draft will be chosen.
// It is assumed that the underlying LDML is canonicalized.
func (cldr *CLDR) SetDraftLevel(lev Draft, preferDraft bool) {
// TODO: implement
cldr.resolved = make(map[string]*LDML)
}
// RawLDML returns the LDML XML for id in unresolved form.
// id must be one of the strings returned by Locales.
func (cldr *CLDR) RawLDML(loc string) *LDML {
return cldr.locale[loc]
}
// LDML returns the fully resolved LDML XML for loc, which must be one of
// the strings returned by Locales.
func (cldr *CLDR) LDML(loc string) (*LDML, error) {
return cldr.resolve(loc)
}
// Supplemental returns the parsed supplemental data. If no such data was parsed,
// nil is returned.
func (cldr *CLDR) Supplemental() *SupplementalData {
return cldr.supp
}
// Locales returns the locales for which there exist files.
// Valid sublocales for which there is no file are not included.
func (cldr *CLDR) Locales() []string {
loc := []string{}
for l, _ := range cldr.locale {
loc = append(loc, l)
}
sort.Strings(loc)
return loc
}
// Get fills in the fields of x based on the XPath path.
func Get(e Elem, path string) (res Elem, err error) {
return walkXPath(e, path)
}
// Copyright 2014 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 cldr
import "testing"
func TestParseDraft(t *testing.T) {
tests := []struct {
in string
draft Draft
err bool
}{
{"unconfirmed", Unconfirmed, false},
{"provisional", Provisional, false},
{"contributed", Contributed, false},
{"approved", Approved, false},
{"", Approved, false},
{"foo", Approved, true},
}
for _, tt := range tests {
if d, err := ParseDraft(tt.in); d != tt.draft || (err != nil) != tt.err {
t.Errorf("%q: was %v, %v; want %v, %v", tt.in, d, err != nil, tt.draft, tt.err)
}
}
}
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package cldr
import (
"bufio"
"encoding/xml"
"errors"
"fmt"
"strconv"
"strings"
"unicode"
"unicode/utf8"
)
// RuleProcessor can be passed to Collator's Process method, which
// parses the rules and calls the respective method for each rule found.
type RuleProcessor interface {
Reset(anchor string, before int) error
Insert(level int, str, context, extend string) error
Index(id string)
}
const (
// cldrIndex is a Unicode-reserved sentinel value used to mark the start
// of a grouping within an index.
// We ignore any rule that starts with this rune.
// See http://unicode.org/reports/tr35/#Collation_Elements for details.
cldrIndex = "\uFDD0"
// specialAnchor is the format in which to represent logical reset positions,
// such as "first tertiary ignorable".
specialAnchor = "<%s/>"
)
// Process parses the rules for the tailorings of this collation
// and calls the respective methods of p for each rule found.
func (c Collation) Process(p RuleProcessor) (err error) {
if len(c.Cr) > 0 {
if len(c.Cr) > 1 {
return fmt.Errorf("multiple cr elements, want 0 or 1")
}
return processRules(p, c.Cr[0].Data())
}
if c.Rules.Any != nil {
return c.processXML(p)
}
return errors.New("no tailoring data")
}
// processRules parses rules in the Collation Rule Syntax defined in
// http://www.unicode.org/reports/tr35/tr35-collation.html#Collation_Tailorings.
func processRules(p RuleProcessor, s string) (err error) {
chk := func(s string, e error) string {
if err == nil {
err = e
}
return s
}
i := 0 // Save the line number for use after the loop.
scanner := bufio.NewScanner(strings.NewReader(s))
for ; scanner.Scan() && err == nil; i++ {
for s := skipSpace(scanner.Text()); s != "" && s[0] != '#'; s = skipSpace(s) {
level := 5
var ch byte
switch ch, s = s[0], s[1:]; ch {
case '&': // followed by <anchor> or '[' <key> ']'
if s = skipSpace(s); consume(&s, '[') {
s = chk(parseSpecialAnchor(p, s))
} else {
s = chk(parseAnchor(p, 0, s))
}
case '<': // sort relation '<'{1,4}, optionally followed by '*'.
for level = 1; consume(&s, '<'); level++ {
}
if level > 4 {
err = fmt.Errorf("level %d > 4", level)
}
fallthrough
case '=': // identity relation, optionally followed by *.
if consume(&s, '*') {
s = chk(parseSequence(p, level, s))
} else {
s = chk(parseOrder(p, level, s))
}
default:
chk("", fmt.Errorf("illegal operator %q", ch))
break
}
}
}
if chk("", scanner.Err()); err != nil {
return fmt.Errorf("%d: %v", i, err)
}
return nil
}
// parseSpecialAnchor parses the anchor syntax which is either of the form
// ['before' <level>] <anchor>
// or
// [<label>]
// The starting should already be consumed.
func parseSpecialAnchor(p RuleProcessor, s string) (tail string, err error) {
i := strings.IndexByte(s, ']')
if i == -1 {
return "", errors.New("unmatched bracket")
}
a := strings.TrimSpace(s[:i])
s = s[i+1:]
if strings.HasPrefix(a, "before ") {
l, err := strconv.ParseUint(skipSpace(a[len("before "):]), 10, 3)
if err != nil {
return s, err
}
return parseAnchor(p, int(l), s)
}
return s, p.Reset(fmt.Sprintf(specialAnchor, a), 0)
}
func parseAnchor(p RuleProcessor, level int, s string) (tail string, err error) {
anchor, s, err := scanString(s)
if err != nil {
return s, err
}
return s, p.Reset(anchor, level)
}
func parseOrder(p RuleProcessor, level int, s string) (tail string, err error) {
var value, context, extend string
if value, s, err = scanString(s); err != nil {
return s, err
}
if strings.HasPrefix(value, cldrIndex) {
p.Index(value[len(cldrIndex):])
return
}
if consume(&s, '|') {
if context, s, err = scanString(s); err != nil {
return s, errors.New("missing string after context")
}
}
if consume(&s, '/') {
if extend, s, err = scanString(s); err != nil {
return s, errors.New("missing string after extension")
}
}
return s, p.Insert(level, value, context, extend)
}
// scanString scans a single input string.
func scanString(s string) (str, tail string, err error) {
if s = skipSpace(s); s == "" {
return s, s, errors.New("missing string")
}
buf := [16]byte{} // small but enough to hold most cases.
value := buf[:0]
for s != "" {
if consume(&s, '\'') {
i := strings.IndexByte(s, '\'')
if i == -1 {
return "", "", errors.New(`unmatched single quote`)
}
if i == 0 {
value = append(value, '\'')
} else {
value = append(value, s[:i]...)
}
s = s[i+1:]
continue
}
r, sz := utf8.DecodeRuneInString(s)
if unicode.IsSpace(r) || strings.ContainsRune("&<=#", r) {
break
}
value = append(value, s[:sz]...)
s = s[sz:]
}
return string(value), skipSpace(s), nil
}
func parseSequence(p RuleProcessor, level int, s string) (tail string, err error) {
if s = skipSpace(s); s == "" {
return s, errors.New("empty sequence")
}
last := rune(0)
for s != "" {
r, sz := utf8.DecodeRuneInString(s)
s = s[sz:]
if r == '-' {
// We have a range. The first element was already written.
if last == 0 {
return s, errors.New("range without starter value")
}
r, sz = utf8.DecodeRuneInString(s)
s = s[sz:]
if r == utf8.RuneError || r < last {
return s, fmt.Errorf("invalid range %q-%q", last, r)
}
for i := last + 1; i <= r; i++ {
if err := p.Insert(level, string(i), "", ""); err != nil {
return s, err
}
}
last = 0
continue
}
if unicode.IsSpace(r) || unicode.IsPunct(r) {
break
}
// normal case
if err := p.Insert(level, string(r), "", ""); err != nil {
return s, err
}
last = r
}
return s, nil
}
func skipSpace(s string) string {
return strings.TrimLeftFunc(s, unicode.IsSpace)
}
// consumes returns whether the next byte is ch. If so, it gobbles it by
// updating s.
func consume(s *string, ch byte) (ok bool) {
if *s == "" || (*s)[0] != ch {
return false
}
*s = (*s)[1:]
return true
}
// The following code parses Collation rules of CLDR version 24 and before.
var lmap = map[byte]int{
'p': 1,
's': 2,
't': 3,
'i': 5,
}
type rulesElem struct {
Rules struct {
Common
Any []*struct {
XMLName xml.Name
rule
} `xml:",any"`
} `xml:"rules"`
}
type rule struct {
Value string `xml:",chardata"`
Before string `xml:"before,attr"`
Any []*struct {
XMLName xml.Name
rule
} `xml:",any"`
}
var emptyValueError = errors.New("cldr: empty rule value")
func (r *rule) value() (string, error) {
// Convert hexadecimal Unicode codepoint notation to a string.
s := charRe.ReplaceAllStringFunc(r.Value, replaceUnicode)
r.Value = s
if s == "" {
if len(r.Any) != 1 {
return "", emptyValueError
}
r.Value = fmt.Sprintf(specialAnchor, r.Any[0].XMLName.Local)
r.Any = nil
} else if len(r.Any) != 0 {
return "", fmt.Errorf("cldr: XML elements found in collation rule: %v", r.Any)
}
return r.Value, nil
}
func (r rule) process(p RuleProcessor, name, context, extend string) error {
v, err := r.value()
if err != nil {
return err
}
switch name {
case "p", "s", "t", "i":
if strings.HasPrefix(v, cldrIndex) {
p.Index(v[len(cldrIndex):])
return nil
}
if err := p.Insert(lmap[name[0]], v, context, extend); err != nil {
return err
}
case "pc", "sc", "tc", "ic":
level := lmap[name[0]]
for _, s := range v {
if err := p.Insert(level, string(s), context, extend); err != nil {
return err
}
}
default:
return fmt.Errorf("cldr: unsupported tag: %q", name)
}
return nil
}
// processXML parses the format of CLDR versions 24 and older.
func (c Collation) processXML(p RuleProcessor) (err error) {
// Collation is generated and defined in xml.go.
var v string
for _, r := range c.Rules.Any {
switch r.XMLName.Local {
case "reset":
level := 0
switch r.Before {
case "primary", "1":
level = 1
case "secondary", "2":
level = 2
case "tertiary", "3":
level = 3
case "":
default:
return fmt.Errorf("cldr: unknown level %q", r.Before)
}
v, err = r.value()
if err == nil {
err = p.Reset(v, level)
}
case "x":
var context, extend string
for _, r1 := range r.Any {
v, err = r1.value()
switch r1.XMLName.Local {
case "context":
context = v
case "extend":
extend = v
}
}
for _, r1 := range r.Any {
if t := r1.XMLName.Local; t == "context" || t == "extend" {
continue
}
r1.rule.process(p, r1.XMLName.Local, context, extend)
}
default:
err = r.rule.process(p, r.XMLName.Local, "", "")
}
if err != nil {
return err
}
}
return nil
}
// Copyright 2014 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 cldr
import (
"fmt"
"strings"
"testing"
)
// A recorder implements the RuleProcessor interface, whereby its methods
// simply record the invocations.
type recorder struct {
calls []string
}
func (r *recorder) Reset(anchor string, before int) error {
if before > 5 {
return fmt.Errorf("before %d > 5", before)
}
r.calls = append(r.calls, fmt.Sprintf("R:%s-%d", anchor, before))
return nil
}
func (r *recorder) Insert(level int, str, context, extend string) error {
s := fmt.Sprintf("O:%d:%s", level, str)
if context != "" {
s += "|" + context
}
if extend != "" {
s += "/" + extend
}
r.calls = append(r.calls, s)
return nil
}
func (r *recorder) Index(id string) {
r.calls = append(r.calls, fmt.Sprintf("I:%s", id))
}
func (r *recorder) Error(err error) {
r.calls = append(r.calls, fmt.Sprintf("E:%v", err))
}
func TestRuleProcessor(t *testing.T) {
for _, tt := range []struct {
desc string
in string
out string
}{
{desc: "empty"},
{desc: "whitespace and comments only",
in: `
# adsfads
# adfadf
`,
},
{
desc: "reset anchor",
in: `
& a
&b #
& [ before 3 ] c
& [before 4] d & ee
& [first tertiary ignorable]
&'g'
& 'h''h'h'h'
&'\u0069' # LATIN SMALL LETTER I
`,
out: `
R:a-0
R:b-0
R:c-3
R:d-4
R:ee-0
R:<first tertiary ignorable/>-0
R:g-0
R:hhhh-0
R:i-0
`,
},
{
desc: "ordering",
in: `
& 0
< 1 <<''2#
<<< 3'3''33'3#
<<<<4
= 5 << 6 | s
<<<< 7 / z
<< 8'' | s / ch
`,
out: `
R:0-0
O:1:1
O:2:'2
O:3:33333
O:4:4
O:5:5
O:2:6|s
O:4:7/z
O:2:8'|s/ch
`,
},
{
desc: "index",
in: "< '\ufdd0'A",
out: "I:A",
},
{
desc: "sequence",
in: `
& 0
<<* 1234
<* a-cde-f
=* q-q
`,
out: `
R:0-0
O:2:1
O:2:2
O:2:3
O:2:4
O:1:a
O:1:b
O:1:c
O:1:d
O:1:e
O:1:f
O:5:q
`,
},
{
desc: "compact",
in: "&B<t<<<T<s<<<S<e<<<E",
out: `
R:B-0
O:1:t
O:3:T
O:1:s
O:3:S
O:1:e
O:3:E
`,
},
{
desc: "err operator",
in: "a",
out: "E:1: illegal operator 'a'",
},
{
desc: "err line number",
in: `& a
<< b
a`,
out: `
R:a-0
O:2:b
E:3: illegal operator 'a'`,
},
{
desc: "err empty anchor",
in: " & ",
out: "E:1: missing string",
},
{
desc: "err anchor invalid special 1",
in: " & [ foo ",
out: "E:1: unmatched bracket",
},
{
desc: "err anchor invalid special 2",
in: "&[",
out: "E:1: unmatched bracket",
},
{
desc: "err anchor invalid before 1",
in: "&[before a]",
out: `E:1: strconv.ParseUint: parsing "a": invalid syntax`,
},
{
desc: "err anchor invalid before 2",
in: "&[before 12]",
out: `E:1: strconv.ParseUint: parsing "12": value out of range`,
},
{
desc: "err anchor invalid before 3",
in: "&[before 2]",
out: "E:1: missing string",
},
{
desc: "err anchor invalid before 4",
in: "&[before 6] a",
out: "E:1: before 6 > 5",
},
{
desc: "err empty order",
in: " < ",
out: "E:1: missing string",
},
{
desc: "err empty identity",
in: " = ",
out: "E:1: missing string",
},
{
desc: "err empty context",
in: " < a | ",
out: "E:1: missing string after context",
},
{
desc: "err empty extend",
in: " < a / ",
out: "E:1: missing string after extension",
},
{
desc: "err empty sequence",
in: " <* ",
out: "E:1: empty sequence",
},
{
desc: "err sequence 1",
in: " <* -a",
out: "E:1: range without starter value",
},
{
desc: "err sequence 3",
in: " <* a-a-b",
out: `O:1:a
E:1: range without starter value
`,
},
{
desc: "err sequence 3",
in: " <* b-a",
out: `O:1:b
E:1: invalid range 'b'-'a'
`,
},
{
desc: "err unmatched quote",
in: " < 'b",
out: ` E:1: unmatched single quote
`,
},
} {
rec := &recorder{}
err := Collation{
Cr: []*Common{
{hidden: hidden{CharData: tt.in}},
},
}.Process(rec)
if err != nil {
rec.Error(err)
}
got := rec.calls
want := strings.Split(strings.TrimSpace(tt.out), "\n")
if tt.out == "" {
want = nil
}
if len(got) != len(want) {
t.Errorf("%s: nResults: got %d; want %d", tt.desc, len(got), len(want))
continue
}
for i, g := range got {
if want := strings.TrimSpace(want[i]); g != want {
t.Errorf("%s:%d: got %q; want %q", tt.desc, i, g, want)
}
}
}
}
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package cldr
// This file contains test data.
import (
"io"
"strings"
)
type testLoader struct {
}
func (t testLoader) Len() int {
return len(testFiles)
}
func (t testLoader) Path(i int) string {
return testPaths[i]
}
func (t testLoader) Reader(i int) (io.ReadCloser, error) {
return &reader{*strings.NewReader(testFiles[i])}, nil
}
// reader adds a dummy Close method to strings.Reader so that it
// satisfies the io.ReadCloser interface.
type reader struct {
strings.Reader
}
func (r reader) Close() error {
return nil
}
var (
testFiles = []string{de_xml, gsw_xml, root_xml}
testPaths = []string{
"common/main/de.xml",
"common/main/gsw.xml",
"common/main/root.xml",
}
)
var root_xml = `<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE ldml SYSTEM "../../common/dtd/ldml.dtd">
<ldml>
<identity>
<language type="root"/>
<generation date="now"/>
</identity>
<characters>
<exemplarCharacters>[]</exemplarCharacters>
<exemplarCharacters type="auxiliary">[]</exemplarCharacters>
<exemplarCharacters type="punctuation">[\- ‐ – — … ' ‘ ‚ &quot; “ „ \&amp; #]</exemplarCharacters>
<ellipsis type="final">{0}…</ellipsis>
<ellipsis type="initial">…{0}</ellipsis>
<moreInformation>?</moreInformation>
</characters>
<dates>
<calendars>
<default choice="gregorian"/>
<calendar type="buddhist">
<months>
<alias source="locale" path="../../calendar[@type='gregorian']/months"/>
</months>
</calendar>
<calendar type="chinese">
<months>
<alias source="locale" path="../../calendar[@type='gregorian']/months"/>
</months>
</calendar>
<calendar type="gregorian">
<months>
<default choice="format"/>
<monthContext type="format">
<default choice="wide"/>
<monthWidth type="narrow">
<alias source="locale" path="../../monthContext[@type='stand-alone']/monthWidth[@type='narrow']"/>
</monthWidth>
<monthWidth type="wide">
<month type="1">11</month>
<month type="2">22</month>
<month type="3">33</month>
<month type="4">44</month>
</monthWidth>
</monthContext>
<monthContext type="stand-alone">
<monthWidth type="narrow">
<month type="1">1</month>
<month type="2">2</month>
<month type="3">3</month>
<month type="4">4</month>
</monthWidth>
<monthWidth type="wide">
<alias source="locale" path="../../monthContext[@type='format']/monthWidth[@type='wide']"/>
</monthWidth>
</monthContext>
</months>
</calendar>
</calendars>
</dates>
</ldml>
`
var de_xml = `<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE ldml SYSTEM "../../common/dtd/ldml.dtd">
<ldml>
<identity>
<language type="de"/>
</identity>
<characters>
<exemplarCharacters>[a ä b c d e ö p q r s ß t u ü v w x y z]</exemplarCharacters>
<exemplarCharacters type="auxiliary">[á à ă]</exemplarCharacters>
<exemplarCharacters type="index">[A B C D E F G H Z]</exemplarCharacters>
<ellipsis type="final">{0} …</ellipsis>
<ellipsis type="initial">… {0}</ellipsis>
<moreInformation>?</moreInformation>
<stopwords>
<stopwordList type="collation" draft="provisional">der die das</stopwordList>
</stopwords>
</characters>
<dates>
<calendars>
<calendar type="buddhist">
<months>
<monthContext type="format">
<monthWidth type="narrow">
<month type="3">BBB</month>
</monthWidth>
<monthWidth type="wide">
<month type="3">bbb</month>
</monthWidth>
</monthContext>
</months>
</calendar>
<calendar type="gregorian">
<months>
<monthContext type="format">
<monthWidth type="narrow">
<month type="3">M</month>
<month type="4">A</month>
</monthWidth>
<monthWidth type="wide">
<month type="3">Maerz</month>
<month type="4">April</month>
<month type="5">Mai</month>
</monthWidth>
</monthContext>
<monthContext type="stand-alone">
<monthWidth type="narrow">
<month type="3">m</month>
<month type="5">m</month>
</monthWidth>
<monthWidth type="wide">
<month type="4">april</month>
<month type="5">mai</month>
</monthWidth>
</monthContext>
</months>
</calendar>
</calendars>
</dates>
<posix>
<messages>
<yesstr>yes:y</yesstr>
<nostr>no:n</nostr>
</messages>
</posix>
</ldml>
`
var gsw_xml = `<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE ldml SYSTEM "../../common/dtd/ldml.dtd">
<ldml>
<identity>
<language type="gsw"/>
</identity>
<posix>
<alias source="de" path="//ldml/posix"/>
</posix>
</ldml>
`
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package cldr
import (
"archive/zip"
"bytes"
"encoding/xml"
"fmt"
"io"
"io/ioutil"
"log"
"os"
"path/filepath"
"regexp"
)
// A Decoder loads an archive of CLDR data.
type Decoder struct {
dirFilter []string
sectionFilter []string
loader Loader
cldr *CLDR
curLocale string
}
// SetSectionFilter takes a list top-level LDML element names to which
// evaluation of LDML should be limited. It automatically calls SetDirFilter.
func (d *Decoder) SetSectionFilter(filter ...string) {
d.sectionFilter = filter
// TODO: automatically set dir filter
}
// SetDirFilter limits the loading of LDML XML files of the specied directories.
// Note that sections may be split across directories differently for different CLDR versions.
// For more robust code, use SetSectionFilter.
func (d *Decoder) SetDirFilter(dir ...string) {
d.dirFilter = dir
}
// A Loader provides access to the files of a CLDR archive.
type Loader interface {
Len() int
Path(i int) string
Reader(i int) (io.ReadCloser, error)
}
var fileRe = regexp.MustCompile(".*/(.*)/(.*)\\.xml")
// Decode loads and decodes the files represented by l.
func (d *Decoder) Decode(l Loader) (cldr *CLDR, err error) {
d.cldr = makeCLDR()
for i := 0; i < l.Len(); i++ {
fname := l.Path(i)
if m := fileRe.FindStringSubmatch(fname); m != nil {
if len(d.dirFilter) > 0 && !in(d.dirFilter, m[1]) {
continue
}
var r io.Reader
if r, err = l.Reader(i); err == nil {
err = d.decode(m[1], m[2], r)
}
if err != nil {
return nil, err
}
}
}
d.cldr.finalize(d.sectionFilter)
return d.cldr, nil
}
func (d *Decoder) decode(dir, id string, r io.Reader) error {
var v interface{}
var l *LDML
cldr := d.cldr
switch {
case dir == "supplemental":
v = cldr.supp
case dir == "transforms":
return nil
case dir == "bcp47":
v = cldr.bcp47
default:
ok := false
if v, ok = cldr.locale[id]; !ok {
l = &LDML{}
v, cldr.locale[id] = l, l
}
}
x := xml.NewDecoder(r)
if err := x.Decode(v); err != nil {
log.Printf("%s/%s: %v", dir, id, err)
return err
}
if l != nil {
if l.Identity == nil {
return fmt.Errorf("%s/%s: missing identity element", dir, id)
}
// TODO: verify when CLDR bug http://unicode.org/cldr/trac/ticket/8970
// is resolved.
// path := strings.Split(id, "_")
// if lang := l.Identity.Language.Type; lang != path[0] {
// return fmt.Errorf("%s/%s: language was %s; want %s", dir, id, lang, path[0])
// }
}
return nil
}
type pathLoader []string
func makePathLoader(path string) (pl pathLoader, err error) {
err = filepath.Walk(path, func(path string, _ os.FileInfo, err error) error {
pl = append(pl, path)
return err
})
return pl, err
}
func (pl pathLoader) Len() int {
return len(pl)
}
func (pl pathLoader) Path(i int) string {
return pl[i]
}
func (pl pathLoader) Reader(i int) (io.ReadCloser, error) {
return os.Open(pl[i])
}
// DecodePath loads CLDR data from the given path.
func (d *Decoder) DecodePath(path string) (cldr *CLDR, err error) {
loader, err := makePathLoader(path)
if err != nil {
return nil, err
}
return d.Decode(loader)
}
type zipLoader struct {
r *zip.Reader
}
func (zl zipLoader) Len() int {
return len(zl.r.File)
}
func (zl zipLoader) Path(i int) string {
return zl.r.File[i].Name
}
func (zl zipLoader) Reader(i int) (io.ReadCloser, error) {
return zl.r.File[i].Open()
}
// DecodeZip loads CLDR data from the zip archive for which r is the source.
func (d *Decoder) DecodeZip(r io.Reader) (cldr *CLDR, err error) {
buffer, err := ioutil.ReadAll(r)
if err != nil {
return nil, err
}
archive, err := zip.NewReader(bytes.NewReader(buffer), int64(len(buffer)))
if err != nil {
return nil, err
}
return d.Decode(zipLoader{archive})
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment