diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json new file mode 100644 index 000000000..ce88b2470 --- /dev/null +++ b/Godeps/Godeps.json @@ -0,0 +1,36 @@ +{ + "ImportPath": "github.com/calmh/syncthing", + "GoVersion": "devel +3ca54dd30864 Sat Mar 22 11:05:40 2014 -0700", + "Packages": [ + "./cmd/syncthing" + ], + "Deps": [ + { + "ImportPath": "code.google.com/p/go.net/ipv6", + "Comment": "null-88", + "Rev": "55437409069bb181ad562b1ad1e5f361c44aff17" + }, + { + "ImportPath": "code.google.com/p/go.text/transform", + "Comment": "null-81", + "Rev": "9cbe983aed9b0dfc73954433fead5e00866342ac" + }, + { + "ImportPath": "code.google.com/p/go.text/unicode/norm", + "Comment": "null-81", + "Rev": "9cbe983aed9b0dfc73954433fead5e00866342ac" + }, + { + "ImportPath": "github.com/calmh/ini", + "Rev": "1020b6d8618a7dc6031cda4a7782324eac346875" + }, + { + "ImportPath": "github.com/codegangsta/inject", + "Rev": "37512bbe41b4cc579cdd706742efc7bf34f94b06" + }, + { + "ImportPath": "github.com/codegangsta/martini", + "Rev": "f86ef0561cc5aa2801d41a7277fd480272ad1556" + } + ] +} diff --git a/Godeps/Readme b/Godeps/Readme new file mode 100644 index 000000000..4cdaa53d5 --- /dev/null +++ b/Godeps/Readme @@ -0,0 +1,5 @@ +This directory tree is generated automatically by godep. + +Please do not edit. + +See https://github.com/tools/godep for more information. diff --git a/Godeps/_workspace/.gitignore b/Godeps/_workspace/.gitignore new file mode 100644 index 000000000..f037d684e --- /dev/null +++ b/Godeps/_workspace/.gitignore @@ -0,0 +1,2 @@ +/pkg +/bin diff --git a/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/control.go b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/control.go new file mode 100644 index 000000000..be06dd674 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/control.go @@ -0,0 +1,84 @@ +// 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 ipv6 + +import ( + "errors" + "fmt" + "net" + "sync" +) + +var ( + errNotSupported = errors.New("not supported") + errMissingAddress = errors.New("missing address") + errInvalidConnType = errors.New("invalid conn type") + errNoSuchInterface = errors.New("no such interface") +) + +// References: +// +// RFC 2292 Advanced Sockets API for IPv6 +// http://tools.ietf.org/html/rfc2292 +// RFC 2460 Internet Protocol, Version 6 (IPv6) Specification +// http://tools.ietf.org/html/rfc2460 +// RFC 3493 Basic Socket Interface Extensions for IPv6 +// http://tools.ietf.org/html/rfc3493.html +// RFC 3542 Advanced Sockets Application Program Interface (API) for IPv6 +// http://tools.ietf.org/html/rfc3542 +// +// Note that RFC 3542 obsoltes RFC 2292 but OS X Snow Leopard and the +// former still support RFC 2292 only. Please be aware that almost +// all protocol implementations prohibit using a combination of RFC +// 2292 and RFC 3542 for some practical reasons. + +type rawOpt struct { + sync.Mutex + cflags ControlFlags +} + +func (c *rawOpt) set(f ControlFlags) { c.cflags |= f } +func (c *rawOpt) clear(f ControlFlags) { c.cflags &^= f } +func (c *rawOpt) isset(f ControlFlags) bool { return c.cflags&f != 0 } + +// A ControlFlags reprensents per packet basis IP-level socket option +// control flags. +type ControlFlags uint + +const ( + FlagTrafficClass ControlFlags = 1 << iota // pass the traffic class on the received packet + FlagHopLimit // pass the hop limit on the received packet + FlagSrc // pass the source address on the received packet + FlagDst // pass the destination address on the received packet + FlagInterface // pass the interface index on the received packet + FlagPathMTU // pass the path MTU on the received packet path +) + +// A ControlMessage represents per packet basis IP-level socket +// options. +type ControlMessage struct { + // Receiving socket options: SetControlMessage allows to + // receive the options from the protocol stack using ReadFrom + // method of PacketConn. + // + // Specifying socket options: ControlMessage for WriteTo + // method of PacketConn allows to send the options to the + // protocol stack. + // + TrafficClass int // traffic class, must be 1 <= value <= 255 when specifying + HopLimit int // hop limit, must be 1 <= value <= 255 when specifying + Src net.IP // source address, specifying only + Dst net.IP // destination address, receiving only + IfIndex int // interface index, must be 1 <= value when specifying + NextHop net.IP // next hop address, specifying only + MTU int // path MTU, receiving only +} + +func (cm *ControlMessage) String() string { + if cm == nil { + return "" + } + return fmt.Sprintf("tclass: %#x, hoplim: %v, src: %v, dst: %v, ifindex: %v, nexthop: %v, mtu: %v", cm.TrafficClass, cm.HopLimit, cm.Src, cm.Dst, cm.IfIndex, cm.NextHop, cm.MTU) +} diff --git a/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/control_rfc2292_darwin.go b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/control_rfc2292_darwin.go new file mode 100644 index 000000000..f09ad7b6f --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/control_rfc2292_darwin.go @@ -0,0 +1,151 @@ +// 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 ipv6 + +import ( + "net" + "os" + "syscall" + "unsafe" +) + +const pktinfo = FlagDst | FlagInterface + +func setControlMessage(fd int, opt *rawOpt, cf ControlFlags, on bool) error { + opt.Lock() + defer opt.Unlock() + if cf&FlagHopLimit != 0 { + if err := setIPv6ReceiveHopLimit(fd, on); err != nil { + return err + } + if on { + opt.set(FlagHopLimit) + } else { + opt.clear(FlagHopLimit) + } + } + if cf&pktinfo != 0 { + if err := setIPv6ReceivePacketInfo(fd, on); err != nil { + return err + } + if on { + opt.set(cf & pktinfo) + } else { + opt.clear(cf & pktinfo) + } + } + return nil +} + +func newControlMessage(opt *rawOpt) (oob []byte) { + opt.Lock() + defer opt.Unlock() + l, off := 0, 0 + if opt.isset(FlagHopLimit) { + l += syscall.CmsgSpace(4) + } + if opt.isset(pktinfo) { + l += syscall.CmsgSpace(syscall.SizeofInet6Pktinfo) + } + if l > 0 { + oob = make([]byte, l) + if opt.isset(FlagHopLimit) { + m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off])) + m.Level = ianaProtocolIPv6 + m.Type = syscall.IPV6_2292HOPLIMIT + m.SetLen(syscall.CmsgLen(4)) + off += syscall.CmsgSpace(4) + } + if opt.isset(pktinfo) { + m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off])) + m.Level = ianaProtocolIPv6 + m.Type = syscall.IPV6_2292PKTINFO + m.SetLen(syscall.CmsgLen(syscall.SizeofInet6Pktinfo)) + off += syscall.CmsgSpace(syscall.SizeofInet6Pktinfo) + } + } + return +} + +func parseControlMessage(b []byte) (*ControlMessage, error) { + if len(b) == 0 { + return nil, nil + } + cmsgs, err := syscall.ParseSocketControlMessage(b) + if err != nil { + return nil, os.NewSyscallError("parse socket control message", err) + } + cm := &ControlMessage{} + for _, m := range cmsgs { + if m.Header.Level != ianaProtocolIPv6 { + continue + } + switch m.Header.Type { + case syscall.IPV6_2292HOPLIMIT: + cm.HopLimit = int(*(*byte)(unsafe.Pointer(&m.Data[:1][0]))) + case syscall.IPV6_2292PKTINFO: + pi := (*syscall.Inet6Pktinfo)(unsafe.Pointer(&m.Data[0])) + cm.IfIndex = int(pi.Ifindex) + cm.Dst = pi.Addr[:] + } + } + return cm, nil +} + +func marshalControlMessage(cm *ControlMessage) (oob []byte) { + if cm == nil { + return + } + l, off := 0, 0 + if cm.HopLimit > 0 { + l += syscall.CmsgSpace(4) + } + pion := false + if cm.Src.To4() == nil && cm.Src.To16() != nil || cm.IfIndex != 0 { + pion = true + l += syscall.CmsgSpace(syscall.SizeofInet6Pktinfo) + } + if len(cm.NextHop) == net.IPv6len { + l += syscall.CmsgSpace(syscall.SizeofSockaddrInet6) + } + if l > 0 { + oob = make([]byte, l) + if cm.HopLimit > 0 { + m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off])) + m.Level = ianaProtocolIPv6 + m.Type = syscall.IPV6_2292HOPLIMIT + m.SetLen(syscall.CmsgLen(4)) + data := oob[off+syscall.CmsgLen(0):] + *(*byte)(unsafe.Pointer(&data[:1][0])) = byte(cm.HopLimit) + off += syscall.CmsgSpace(4) + } + if pion { + m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off])) + m.Level = ianaProtocolIPv6 + m.Type = syscall.IPV6_2292PKTINFO + m.SetLen(syscall.CmsgLen(syscall.SizeofInet6Pktinfo)) + pi := (*syscall.Inet6Pktinfo)(unsafe.Pointer(&oob[off+syscall.CmsgLen(0)])) + if ip := cm.Src.To16(); ip != nil && ip.To4() == nil { + copy(pi.Addr[:], ip) + } + if cm.IfIndex != 0 { + pi.Ifindex = uint32(cm.IfIndex) + } + off += syscall.CmsgSpace(syscall.SizeofInet6Pktinfo) + } + if len(cm.NextHop) == net.IPv6len { + m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off])) + m.Level = ianaProtocolIPv6 + m.Type = syscall.IPV6_2292NEXTHOP + m.SetLen(syscall.CmsgLen(syscall.SizeofSockaddrInet6)) + sa := (*syscall.RawSockaddrInet6)(unsafe.Pointer(&oob[off+syscall.CmsgLen(0)])) + sa.Len = syscall.SizeofSockaddrInet6 + sa.Family = syscall.AF_INET6 + copy(sa.Addr[:], cm.NextHop) + off += syscall.CmsgSpace(syscall.SizeofSockaddrInet6) + } + } + return +} diff --git a/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/control_rfc3542_bsd.go b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/control_rfc3542_bsd.go new file mode 100644 index 000000000..0b42c0b71 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/control_rfc3542_bsd.go @@ -0,0 +1,213 @@ +// 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. + +// +build freebsd netbsd openbsd + +package ipv6 + +import ( + "net" + "os" + "syscall" + "unsafe" +) + +const pktinfo = FlagDst | FlagInterface + +func setControlMessage(fd int, opt *rawOpt, cf ControlFlags, on bool) error { + opt.Lock() + defer opt.Unlock() + if cf&FlagTrafficClass != 0 { + if err := setIPv6ReceiveTrafficClass(fd, on); err != nil { + return err + } + if on { + opt.set(FlagTrafficClass) + } else { + opt.clear(FlagTrafficClass) + } + } + if cf&FlagHopLimit != 0 { + if err := setIPv6ReceiveHopLimit(fd, on); err != nil { + return err + } + if on { + opt.set(FlagHopLimit) + } else { + opt.clear(FlagHopLimit) + } + } + if cf&pktinfo != 0 { + if err := setIPv6ReceivePacketInfo(fd, on); err != nil { + return err + } + if on { + opt.set(cf & pktinfo) + } else { + opt.clear(cf & pktinfo) + } + } + if cf&FlagPathMTU != 0 { + if err := setIPv6ReceivePathMTU(fd, on); err != nil { + return err + } + if on { + opt.set(FlagPathMTU) + } else { + opt.clear(FlagPathMTU) + } + } + return nil +} + +func newControlMessage(opt *rawOpt) (oob []byte) { + opt.Lock() + defer opt.Unlock() + l, off := 0, 0 + if opt.isset(FlagTrafficClass) { + l += syscall.CmsgSpace(4) + } + if opt.isset(FlagHopLimit) { + l += syscall.CmsgSpace(4) + } + if opt.isset(pktinfo) { + l += syscall.CmsgSpace(syscall.SizeofInet6Pktinfo) + } + if opt.isset(FlagPathMTU) { + l += syscall.CmsgSpace(syscall.SizeofIPv6MTUInfo) + } + if l > 0 { + oob = make([]byte, l) + if opt.isset(FlagTrafficClass) { + m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off])) + m.Level = ianaProtocolIPv6 + m.Type = syscall.IPV6_RECVTCLASS + m.SetLen(syscall.CmsgLen(4)) + off += syscall.CmsgSpace(4) + } + if opt.isset(FlagHopLimit) { + m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off])) + m.Level = ianaProtocolIPv6 + m.Type = syscall.IPV6_RECVHOPLIMIT + m.SetLen(syscall.CmsgLen(4)) + off += syscall.CmsgSpace(4) + } + if opt.isset(pktinfo) { + m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off])) + m.Level = ianaProtocolIPv6 + m.Type = syscall.IPV6_RECVPKTINFO + m.SetLen(syscall.CmsgLen(syscall.SizeofInet6Pktinfo)) + off += syscall.CmsgSpace(syscall.SizeofInet6Pktinfo) + } + if opt.isset(FlagPathMTU) { + m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off])) + m.Level = ianaProtocolIPv6 + m.Type = syscall.IPV6_RECVPATHMTU + m.SetLen(syscall.CmsgLen(syscall.SizeofIPv6MTUInfo)) + off += syscall.CmsgSpace(syscall.SizeofIPv6MTUInfo) + } + } + return +} + +func parseControlMessage(b []byte) (*ControlMessage, error) { + if len(b) == 0 { + return nil, nil + } + cmsgs, err := syscall.ParseSocketControlMessage(b) + if err != nil { + return nil, os.NewSyscallError("parse socket control message", err) + } + cm := &ControlMessage{} + for _, m := range cmsgs { + if m.Header.Level != ianaProtocolIPv6 { + continue + } + switch m.Header.Type { + case syscall.IPV6_TCLASS: + cm.TrafficClass = int(*(*byte)(unsafe.Pointer(&m.Data[:1][0]))) + case syscall.IPV6_HOPLIMIT: + cm.HopLimit = int(*(*byte)(unsafe.Pointer(&m.Data[:1][0]))) + case syscall.IPV6_PKTINFO: + pi := (*syscall.Inet6Pktinfo)(unsafe.Pointer(&m.Data[0])) + cm.Dst = pi.Addr[:] + cm.IfIndex = int(pi.Ifindex) + case syscall.IPV6_PATHMTU: + mi := (*syscall.IPv6MTUInfo)(unsafe.Pointer(&m.Data[0])) + cm.Dst = mi.Addr.Addr[:] + cm.IfIndex = int(mi.Addr.Scope_id) + cm.MTU = int(mi.Mtu) + } + } + return cm, nil +} + +func marshalControlMessage(cm *ControlMessage) (oob []byte) { + if cm == nil { + return + } + l, off := 0, 0 + if cm.TrafficClass > 0 { + l += syscall.CmsgSpace(4) + } + if cm.HopLimit > 0 { + l += syscall.CmsgSpace(4) + } + pion := false + if cm.Src.To4() == nil && cm.Src.To16() != nil || cm.IfIndex != 0 { + pion = true + l += syscall.CmsgSpace(syscall.SizeofInet6Pktinfo) + } + if len(cm.NextHop) == net.IPv6len { + l += syscall.CmsgSpace(syscall.SizeofSockaddrInet6) + } + if l > 0 { + oob = make([]byte, l) + if cm.TrafficClass > 0 { + m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off])) + m.Level = ianaProtocolIPv6 + m.Type = syscall.IPV6_TCLASS + m.SetLen(syscall.CmsgLen(4)) + data := oob[off+syscall.CmsgLen(0):] + *(*byte)(unsafe.Pointer(&data[:1][0])) = byte(cm.TrafficClass) + off += syscall.CmsgSpace(4) + } + if cm.HopLimit > 0 { + m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off])) + m.Level = ianaProtocolIPv6 + m.Type = syscall.IPV6_HOPLIMIT + m.SetLen(syscall.CmsgLen(4)) + data := oob[off+syscall.CmsgLen(0):] + *(*byte)(unsafe.Pointer(&data[:1][0])) = byte(cm.HopLimit) + off += syscall.CmsgSpace(4) + } + if pion { + m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off])) + m.Level = ianaProtocolIPv6 + m.Type = syscall.IPV6_PKTINFO + m.SetLen(syscall.CmsgLen(syscall.SizeofInet6Pktinfo)) + pi := (*syscall.Inet6Pktinfo)(unsafe.Pointer(&oob[off+syscall.CmsgLen(0)])) + if ip := cm.Src.To16(); ip != nil && ip.To4() == nil { + copy(pi.Addr[:], ip) + } + if cm.IfIndex != 0 { + pi.Ifindex = uint32(cm.IfIndex) + } + off += syscall.CmsgSpace(syscall.SizeofInet6Pktinfo) + } + if len(cm.NextHop) == net.IPv6len { + m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off])) + m.Level = ianaProtocolIPv6 + m.Type = syscall.IPV6_NEXTHOP + m.SetLen(syscall.CmsgLen(syscall.SizeofSockaddrInet6)) + sa := (*syscall.RawSockaddrInet6)(unsafe.Pointer(&oob[off+syscall.CmsgLen(0)])) + sa.Len = syscall.SizeofSockaddrInet6 + sa.Family = syscall.AF_INET6 + copy(sa.Addr[:], cm.NextHop) + sa.Scope_id = uint32(cm.IfIndex) + off += syscall.CmsgSpace(syscall.SizeofSockaddrInet6) + } + } + return +} diff --git a/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/control_rfc3542_linux.go b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/control_rfc3542_linux.go new file mode 100644 index 000000000..3e73f3b16 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/control_rfc3542_linux.go @@ -0,0 +1,217 @@ +// 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 ipv6 + +import ( + "net" + "os" + "syscall" + "unsafe" +) + +const ( + // See /usr/include/linux/in6.h. + syscall_IPV6_RECVPATHMTU = syscall.IPV6_DSTOPTS + 1 + iota + syscall_IPV6_PATHMTU + syscall_IPV6_DONTFRAG +) + +const pktinfo = FlagDst | FlagInterface + +func setControlMessage(fd int, opt *rawOpt, cf ControlFlags, on bool) error { + opt.Lock() + defer opt.Unlock() + if cf&FlagTrafficClass != 0 { + if err := setIPv6ReceiveTrafficClass(fd, on); err != nil { + return err + } + if on { + opt.set(FlagTrafficClass) + } else { + opt.clear(FlagTrafficClass) + } + } + if cf&FlagHopLimit != 0 { + if err := setIPv6ReceiveHopLimit(fd, on); err != nil { + return err + } + if on { + opt.set(FlagHopLimit) + } else { + opt.clear(FlagHopLimit) + } + } + if cf&pktinfo != 0 { + if err := setIPv6ReceivePacketInfo(fd, on); err != nil { + return err + } + if on { + opt.set(cf & pktinfo) + } else { + opt.clear(cf & pktinfo) + } + } + if cf&FlagPathMTU != 0 { + if err := setIPv6ReceivePathMTU(fd, on); err != nil { + return err + } + if on { + opt.set(FlagPathMTU) + } else { + opt.clear(FlagPathMTU) + } + } + return nil +} + +func newControlMessage(opt *rawOpt) (oob []byte) { + opt.Lock() + defer opt.Unlock() + l, off := 0, 0 + if opt.isset(FlagTrafficClass) { + l += syscall.CmsgSpace(4) + } + if opt.isset(FlagHopLimit) { + l += syscall.CmsgSpace(4) + } + if opt.isset(pktinfo) { + l += syscall.CmsgSpace(syscall.SizeofInet6Pktinfo) + } + if opt.isset(FlagPathMTU) { + l += syscall.CmsgSpace(syscall.SizeofIPv6MTUInfo) + } + if l > 0 { + oob = make([]byte, l) + if opt.isset(FlagTrafficClass) { + m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off])) + m.Level = ianaProtocolIPv6 + m.Type = syscall.IPV6_RECVTCLASS + m.SetLen(syscall.CmsgLen(4)) + off += syscall.CmsgSpace(4) + } + if opt.isset(FlagHopLimit) { + m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off])) + m.Level = ianaProtocolIPv6 + m.Type = syscall.IPV6_RECVHOPLIMIT + m.SetLen(syscall.CmsgLen(4)) + off += syscall.CmsgSpace(4) + } + if opt.isset(pktinfo) { + m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off])) + m.Level = ianaProtocolIPv6 + m.Type = syscall.IPV6_RECVPKTINFO + m.SetLen(syscall.CmsgLen(syscall.SizeofInet6Pktinfo)) + off += syscall.CmsgSpace(syscall.SizeofInet6Pktinfo) + } + if opt.isset(FlagPathMTU) { + m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off])) + m.Level = ianaProtocolIPv6 + m.Type = syscall_IPV6_RECVPATHMTU + m.SetLen(syscall.CmsgLen(syscall.SizeofIPv6MTUInfo)) + off += syscall.CmsgSpace(syscall.SizeofIPv6MTUInfo) + } + } + return +} + +func parseControlMessage(b []byte) (*ControlMessage, error) { + if len(b) == 0 { + return nil, nil + } + cmsgs, err := syscall.ParseSocketControlMessage(b) + if err != nil { + return nil, os.NewSyscallError("parse socket control message", err) + } + cm := &ControlMessage{} + for _, m := range cmsgs { + if m.Header.Level != ianaProtocolIPv6 { + continue + } + switch m.Header.Type { + case syscall.IPV6_TCLASS: + cm.TrafficClass = int(*(*byte)(unsafe.Pointer(&m.Data[:1][0]))) + case syscall.IPV6_HOPLIMIT: + cm.HopLimit = int(*(*byte)(unsafe.Pointer(&m.Data[:1][0]))) + case syscall.IPV6_PKTINFO: + pi := (*syscall.Inet6Pktinfo)(unsafe.Pointer(&m.Data[0])) + cm.Dst = pi.Addr[:] + cm.IfIndex = int(pi.Ifindex) + case syscall_IPV6_PATHMTU: + mi := (*syscall.IPv6MTUInfo)(unsafe.Pointer(&m.Data[0])) + cm.Dst = mi.Addr.Addr[:] + cm.IfIndex = int(mi.Addr.Scope_id) + cm.MTU = int(mi.Mtu) + } + } + return cm, nil +} + +func marshalControlMessage(cm *ControlMessage) (oob []byte) { + if cm == nil { + return + } + l, off := 0, 0 + if cm.TrafficClass > 0 { + l += syscall.CmsgSpace(4) + } + if cm.HopLimit > 0 { + l += syscall.CmsgSpace(4) + } + pion := false + if cm.Src.To4() == nil && cm.Src.To16() != nil || cm.IfIndex != 0 { + pion = true + l += syscall.CmsgSpace(syscall.SizeofInet6Pktinfo) + } + if len(cm.NextHop) == net.IPv6len { + l += syscall.CmsgSpace(syscall.SizeofSockaddrInet6) + } + if l > 0 { + oob = make([]byte, l) + if cm.TrafficClass > 0 { + m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off])) + m.Level = ianaProtocolIPv6 + m.Type = syscall.IPV6_TCLASS + m.SetLen(syscall.CmsgLen(4)) + data := oob[off+syscall.CmsgLen(0):] + *(*byte)(unsafe.Pointer(&data[:1][0])) = byte(cm.TrafficClass) + off += syscall.CmsgSpace(4) + } + if cm.HopLimit > 0 { + m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off])) + m.Level = ianaProtocolIPv6 + m.Type = syscall.IPV6_HOPLIMIT + m.SetLen(syscall.CmsgLen(4)) + data := oob[off+syscall.CmsgLen(0):] + *(*byte)(unsafe.Pointer(&data[:1][0])) = byte(cm.HopLimit) + off += syscall.CmsgSpace(4) + } + if pion { + m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off])) + m.Level = ianaProtocolIPv6 + m.Type = syscall.IPV6_PKTINFO + m.SetLen(syscall.CmsgLen(syscall.SizeofInet6Pktinfo)) + pi := (*syscall.Inet6Pktinfo)(unsafe.Pointer(&oob[off+syscall.CmsgLen(0)])) + if ip := cm.Src.To16(); ip != nil && ip.To4() == nil { + copy(pi.Addr[:], ip) + } + if cm.IfIndex != 0 { + pi.Ifindex = uint32(cm.IfIndex) + } + off += syscall.CmsgSpace(syscall.SizeofInet6Pktinfo) + } + if len(cm.NextHop) == net.IPv6len { + m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off])) + m.Level = ianaProtocolIPv6 + m.Type = syscall.IPV6_NEXTHOP + m.SetLen(syscall.CmsgLen(syscall.SizeofSockaddrInet6)) + sa := (*syscall.RawSockaddrInet6)(unsafe.Pointer(&oob[off+syscall.CmsgLen(0)])) + sa.Family = syscall.AF_INET6 + copy(sa.Addr[:], cm.NextHop) + sa.Scope_id = uint32(cm.IfIndex) + off += syscall.CmsgSpace(syscall.SizeofSockaddrInet6) + } + } + return +} diff --git a/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/control_rfc3542_plan9.go b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/control_rfc3542_plan9.go new file mode 100644 index 000000000..052b229f6 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/control_rfc3542_plan9.go @@ -0,0 +1,27 @@ +// 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 ipv6 + +import "syscall" + +func setControlMessage(fd int, opt *rawOpt, cf ControlFlags, on bool) error { + // TODO(mikio): Implement this + return syscall.EPLAN9 +} + +func newControlMessage(opt *rawOpt) (oob []byte) { + // TODO(mikio): Implement this + return nil +} + +func parseControlMessage(b []byte) (*ControlMessage, error) { + // TODO(mikio): Implement this + return nil, syscall.EPLAN9 +} + +func marshalControlMessage(cm *ControlMessage) (oob []byte) { + // TODO(mikio): Implement this + return nil +} diff --git a/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/control_rfc3542_windows.go b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/control_rfc3542_windows.go new file mode 100644 index 000000000..b4d53fb65 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/control_rfc3542_windows.go @@ -0,0 +1,27 @@ +// 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 ipv6 + +import "syscall" + +func setControlMessage(fd syscall.Handle, opt *rawOpt, cf ControlFlags, on bool) error { + // TODO(mikio): Implement this + return syscall.EWINDOWS +} + +func newControlMessage(opt *rawOpt) (oob []byte) { + // TODO(mikio): Implement this + return nil +} + +func parseControlMessage(b []byte) (*ControlMessage, error) { + // TODO(mikio): Implement this + return nil, syscall.EWINDOWS +} + +func marshalControlMessage(cm *ControlMessage) (oob []byte) { + // TODO(mikio): Implement this + return nil +} diff --git a/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/control_test.go b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/control_test.go new file mode 100644 index 000000000..0f993210b --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/control_test.go @@ -0,0 +1,42 @@ +// 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 ipv6 + +import ( + "sync" + "testing" +) + +func TestControlFlags(t *testing.T) { + tf := FlagInterface | FlagPathMTU + opt := rawOpt{cflags: tf | FlagHopLimit} + + // This loop runs methods of raw.Opt concurrently for testing + // concurrent access to the rawOpt. The first entry shold be + // opt.set and the last entry should be opt.clear. + tfns := []func(ControlFlags){opt.set, opt.clear, opt.clear} + ch := make(chan bool) + var wg sync.WaitGroup + for i, fn := range tfns { + wg.Add(1) + go func(i int, fn func(ControlFlags)) { + defer wg.Done() + switch i { + case 0: + close(ch) + case len(tfns) - 1: + <-ch + } + opt.Lock() + defer opt.Unlock() + fn(tf) + }(i, fn) + } + wg.Wait() + + if opt.isset(tf) { + t.Fatalf("got %#x; expected %#x", opt.cflags, FlagHopLimit) + } +} diff --git a/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/dgramopt_plan9.go b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/dgramopt_plan9.go new file mode 100644 index 000000000..4c26be259 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/dgramopt_plan9.go @@ -0,0 +1,96 @@ +// 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 ipv6 + +import ( + "net" + "syscall" +) + +// MulticastHopLimit returns the hop limit field value for outgoing +// multicast packets. +func (c *dgramOpt) MulticastHopLimit() (int, error) { + // TODO(mikio): Implement this + return 0, syscall.EPLAN9 +} + +// SetMulticastHopLimit sets the hop limit field value for future +// outgoing multicast packets. +func (c *dgramOpt) SetMulticastHopLimit(hoplim int) error { + // TODO(mikio): Implement this + return syscall.EPLAN9 +} + +// MulticastInterface returns the default interface for multicast +// packet transmissions. +func (c *dgramOpt) MulticastInterface() (*net.Interface, error) { + // TODO(mikio): Implement this + return nil, syscall.EPLAN9 +} + +// SetMulticastInterface sets the default interface for future +// multicast packet transmissions. +func (c *dgramOpt) SetMulticastInterface(ifi *net.Interface) error { + // TODO(mikio): Implement this + return syscall.EPLAN9 +} + +// MulticastLoopback reports whether transmitted multicast packets +// should be copied and send back to the originator. +func (c *dgramOpt) MulticastLoopback() (bool, error) { + // TODO(mikio): Implement this + return false, syscall.EPLAN9 +} + +// SetMulticastLoopback sets whether transmitted multicast packets +// should be copied and send back to the originator. +func (c *dgramOpt) SetMulticastLoopback(on bool) error { + // TODO(mikio): Implement this + return syscall.EPLAN9 +} + +// JoinGroup joins the group address group on the interface ifi. +// It uses the system assigned multicast interface when ifi is nil, +// although this is not recommended because the assignment depends on +// platforms and sometimes it might require routing configuration. +func (c *dgramOpt) JoinGroup(ifi *net.Interface, group net.Addr) error { + // TODO(mikio): Implement this + return syscall.EPLAN9 +} + +// LeaveGroup leaves the group address group on the interface ifi. +func (c *dgramOpt) LeaveGroup(ifi *net.Interface, group net.Addr) error { + // TODO(mikio): Implement this + return syscall.EPLAN9 +} + +// Checksum reports whether the kernel will compute, store or verify a +// checksum for both incoming and outgoing packets. If on is true, it +// returns an offset in bytes into the data of where the checksum +// field is located. +func (c *dgramOpt) Checksum() (on bool, offset int, err error) { + // TODO(mikio): Implement this + return false, 0, syscall.EPLAN9 +} + +// SetChecksum enables the kernel checksum processing. If on is ture, +// the offset should be an offset in bytes into the data of where the +// checksum field is located. +func (c *dgramOpt) SetChecksum(on bool, offset int) error { + // TODO(mikio): Implement this + return syscall.EPLAN9 +} + +// ICMPFilter returns an ICMP filter. +func (c *dgramOpt) ICMPFilter() (*ICMPFilter, error) { + // TODO(mikio): Implement this + return nil, syscall.EPLAN9 +} + +// SetICMPFilter deploys the ICMP filter. +func (c *dgramOpt) SetICMPFilter(f *ICMPFilter) error { + // TODO(mikio): Implement this + return syscall.EPLAN9 +} diff --git a/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/dgramopt_posix.go b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/dgramopt_posix.go new file mode 100644 index 000000000..c52f48dab --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/dgramopt_posix.go @@ -0,0 +1,178 @@ +// 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. + +// +build darwin freebsd linux netbsd openbsd windows + +package ipv6 + +import ( + "net" + "syscall" +) + +// MulticastHopLimit returns the hop limit field value for outgoing +// multicast packets. +func (c *dgramOpt) MulticastHopLimit() (int, error) { + if !c.ok() { + return 0, syscall.EINVAL + } + fd, err := c.sysfd() + if err != nil { + return 0, err + } + return ipv6MulticastHopLimit(fd) +} + +// SetMulticastHopLimit sets the hop limit field value for future +// outgoing multicast packets. +func (c *dgramOpt) SetMulticastHopLimit(hoplim int) error { + if !c.ok() { + return syscall.EINVAL + } + fd, err := c.sysfd() + if err != nil { + return err + } + return setIPv6MulticastHopLimit(fd, hoplim) +} + +// MulticastInterface returns the default interface for multicast +// packet transmissions. +func (c *dgramOpt) MulticastInterface() (*net.Interface, error) { + if !c.ok() { + return nil, syscall.EINVAL + } + fd, err := c.sysfd() + if err != nil { + return nil, err + } + return ipv6MulticastInterface(fd) +} + +// SetMulticastInterface sets the default interface for future +// multicast packet transmissions. +func (c *dgramOpt) SetMulticastInterface(ifi *net.Interface) error { + if !c.ok() { + return syscall.EINVAL + } + fd, err := c.sysfd() + if err != nil { + return err + } + return setIPv6MulticastInterface(fd, ifi) +} + +// MulticastLoopback reports whether transmitted multicast packets +// should be copied and send back to the originator. +func (c *dgramOpt) MulticastLoopback() (bool, error) { + if !c.ok() { + return false, syscall.EINVAL + } + fd, err := c.sysfd() + if err != nil { + return false, err + } + return ipv6MulticastLoopback(fd) +} + +// SetMulticastLoopback sets whether transmitted multicast packets +// should be copied and send back to the originator. +func (c *dgramOpt) SetMulticastLoopback(on bool) error { + if !c.ok() { + return syscall.EINVAL + } + fd, err := c.sysfd() + if err != nil { + return err + } + return setIPv6MulticastLoopback(fd, on) +} + +// JoinGroup joins the group address group on the interface ifi. +// It uses the system assigned multicast interface when ifi is nil, +// although this is not recommended because the assignment depends on +// platforms and sometimes it might require routing configuration. +func (c *dgramOpt) JoinGroup(ifi *net.Interface, group net.Addr) error { + if !c.ok() { + return syscall.EINVAL + } + fd, err := c.sysfd() + if err != nil { + return err + } + grp := netAddrToIP16(group) + if grp == nil { + return errMissingAddress + } + return joinIPv6Group(fd, ifi, grp) +} + +// LeaveGroup leaves the group address group on the interface ifi. +func (c *dgramOpt) LeaveGroup(ifi *net.Interface, group net.Addr) error { + if !c.ok() { + return syscall.EINVAL + } + fd, err := c.sysfd() + if err != nil { + return err + } + grp := netAddrToIP16(group) + if grp == nil { + return errMissingAddress + } + return leaveIPv6Group(fd, ifi, grp) +} + +// Checksum reports whether the kernel will compute, store or verify a +// checksum for both incoming and outgoing packets. If on is true, it +// returns an offset in bytes into the data of where the checksum +// field is located. +func (c *dgramOpt) Checksum() (on bool, offset int, err error) { + if !c.ok() { + return false, 0, syscall.EINVAL + } + fd, err := c.sysfd() + if err != nil { + return false, 0, err + } + return ipv6Checksum(fd) +} + +// SetChecksum enables the kernel checksum processing. If on is ture, +// the offset should be an offset in bytes into the data of where the +// checksum field is located. +func (c *dgramOpt) SetChecksum(on bool, offset int) error { + if !c.ok() { + return syscall.EINVAL + } + fd, err := c.sysfd() + if err != nil { + return err + } + return setIPv6Checksum(fd, on, offset) +} + +// ICMPFilter returns an ICMP filter. +func (c *dgramOpt) ICMPFilter() (*ICMPFilter, error) { + if !c.ok() { + return nil, syscall.EINVAL + } + fd, err := c.sysfd() + if err != nil { + return nil, err + } + return ipv6ICMPFilter(fd) +} + +// SetICMPFilter deploys the ICMP filter. +func (c *dgramOpt) SetICMPFilter(f *ICMPFilter) error { + if !c.ok() { + return syscall.EINVAL + } + fd, err := c.sysfd() + if err != nil { + return err + } + return setIPv6ICMPFilter(fd, f) +} diff --git a/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/doc.go b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/doc.go new file mode 100644 index 000000000..b4578c586 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/doc.go @@ -0,0 +1,193 @@ +// 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 ipv6 implements IP-level socket options for the Internet +// Protocol version 6. +// +// The package provides IP-level socket options that allow +// manipulation of IPv6 facilities. The IPv6 and socket options for +// IPv6 are defined in RFC 2460, RFC 3493 and RFC 3542. +// +// +// Unicasting +// +// The options for unicasting are available for net.TCPConn, +// net.UDPConn and net.IPConn which are created as network connections +// that use the IPv6 transport. When a single TCP connection carrying +// a data flow of multiple packets needs to indicate the flow is +// important, ipv6.Conn is used to set the traffic class field on the +// IPv6 header for each packet. +// +// ln, err := net.Listen("tcp6", "[::]:1024") +// if err != nil { +// // error handling +// } +// defer ln.Close() +// for { +// c, err := ln.Accept() +// if err != nil { +// // error handling +// } +// go func(c net.Conn) { +// defer c.Close() +// +// The outgoing packets will be labeled DiffServ assured forwarding +// class 1 low drop precedence, as known as AF11 packets. +// +// if err := ipv6.NewConn(c).SetTrafficClass(DiffServAF11); err != nil { +// // error handling +// } +// if _, err := c.Write(data); err != nil { +// // error handling +// } +// }(c) +// } +// +// +// Multicasting +// +// The options for multicasting are available for net.UDPConn and +// net.IPconn which are created as network connections that use the +// IPv6 transport. A few network facilities must be prepared before +// you begin multicasting, at a minimum joining network interfaces and +// multicast groups. +// +// en0, err := net.InterfaceByName("en0") +// if err != nil { +// // error handling +// } +// en1, err := net.InterfaceByIndex(911) +// if err != nil { +// // error handling +// } +// group := net.ParseIP("ff02::114") +// +// First, an application listens to an appropriate address with an +// appropriate service port. +// +// c, err := net.ListenPacket("udp6", "[::]:1024") +// if err != nil { +// // error handling +// } +// defer c.Close() +// +// Second, the application joins multicast groups, starts listening to +// the groups on the specified network interfaces. Note that the +// service port for transport layer protocol does not matter with this +// operation as joining groups affects only network and link layer +// protocols, such as IPv6 and Ethernet. +// +// p := ipv6.NewPacketConn(c) +// if err := p.JoinGroup(en0, &net.UDPAddr{IP: group}); err != nil { +// // error handling +// } +// if err := p.JoinGroup(en1, &net.UDPAddr{IP: group}); err != nil { +// // error handling +// } +// +// The application might set per packet control message transmissions +// between the protocol stack within the kernel. When the application +// needs a destination address on an incoming packet, +// SetControlMessage of ipv6.PacketConn is used to enable control +// message transmissons. +// +// if err := p.SetControlMessage(ipv6.FlagDst, true); err != nil { +// // error handling +// } +// +// The application could identify whether the received packets are +// of interest by using the control message that contains the +// destination address of the received packet. +// +// b := make([]byte, 1500) +// for { +// n, rcm, src, err := p.ReadFrom(b) +// if err != nil { +// // error handling +// } +// if rcm.Dst.IsMulticast() { +// if rcm.Dst.Equal(group) +// // joined group, do something +// } else { +// // unknown group, discard +// continue +// } +// } +// +// The application can also send both unicast and multicast packets. +// +// p.SetTrafficClass(DiffServCS0) +// p.SetHopLimit(16) +// if _, err := p.WriteTo(data[:n], nil, src); err != nil { +// // error handling +// } +// dst := &net.UDPAddr{IP: group, Port: 1024} +// wcm := ipv6.ControlMessage{TrafficClass: DiffServCS7, HopLimit: 1} +// for _, ifi := range []*net.Interface{en0, en1} { +// wcm.IfIndex = ifi.Index +// if _, err := p.WriteTo(data[:n], &wcm, dst); err != nil { +// // error handling +// } +// } +// } +// +// +// More multicasting +// +// An application that uses PacketConn may join multiple multicast +// groups. For example, a UDP listener with port 1024 might join two +// different groups across over two different network interfaces by +// using: +// +// c, err := net.ListenPacket("udp6", "[::]:1024") +// if err != nil { +// // error handling +// } +// defer c.Close() +// p := ipv6.NewPacketConn(c) +// if err := p.JoinGroup(en0, &net.UDPAddr{IP: net.ParseIP("ff02::1:114")}); err != nil { +// // error handling +// } +// if err := p.JoinGroup(en0, &net.UDPAddr{IP: net.ParseIP("ff02::2:114")}); err != nil { +// // error handling +// } +// if err := p.JoinGroup(en1, &net.UDPAddr{IP: net.ParseIP("ff02::2:114")}); err != nil { +// // error handling +// } +// +// It is possible for multiple UDP listeners that listen on the same +// UDP port to join the same multicast group. The net package will +// provide a socket that listens to a wildcard address with reusable +// UDP port when an appropriate multicast address prefix is passed to +// the net.ListenPacket or net.ListenUDP. +// +// c1, err := net.ListenPacket("udp6", "[ff02::]:1024") +// if err != nil { +// // error handling +// } +// defer c1.Close() +// c2, err := net.ListenPacket("udp6", "[ff02::]:1024") +// if err != nil { +// // error handling +// } +// defer c2.Close() +// p1 := ipv6.NewPacketConn(c1) +// if err := p1.JoinGroup(en0, &net.UDPAddr{IP: net.ParseIP("ff02::114")}); err != nil { +// // error handling +// } +// p2 := ipv6.NewPacketConn(c2) +// if err := p2.JoinGroup(en0, &net.UDPAddr{IP: net.ParseIP("ff02::114")}); err != nil { +// // error handling +// } +// +// Also it is possible for the application to leave or rejoin a +// multicast group on the network interface. +// +// if err := p.LeaveGroup(en0, &net.UDPAddr{IP: net.ParseIP("ff02::114")}); err != nil { +// // error handling +// } +// if err := p.JoinGroup(en0, &net.UDPAddr{IP: net.ParseIP("ff01::114")}); err != nil { +// // error handling +// } +package ipv6 diff --git a/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/endpoint.go b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/endpoint.go new file mode 100644 index 000000000..04eee35fa --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/endpoint.go @@ -0,0 +1,119 @@ +// 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 ipv6 + +import ( + "net" + "syscall" + "time" +) + +// A Conn represents a network endpoint that uses IPv6 transport. +// It allows to set basic IP-level socket options such as traffic +// class and hop limit. +type Conn struct { + genericOpt +} + +type genericOpt struct { + net.Conn +} + +func (c *genericOpt) ok() bool { return c != nil && c.Conn != nil } + +// PathMTU returns a path MTU value for the destination associated +// with the endpoint. +func (c *Conn) PathMTU() (int, error) { + if !c.genericOpt.ok() { + return 0, syscall.EINVAL + } + fd, err := c.genericOpt.sysfd() + if err != nil { + return 0, err + } + return ipv6PathMTU(fd) +} + +// NewConn returns a new Conn. +func NewConn(c net.Conn) *Conn { + return &Conn{ + genericOpt: genericOpt{Conn: c}, + } +} + +// A PacketConn represents a packet network endpoint that uses IPv6 +// transport. It is used to control several IP-level socket options +// including IPv6 header manipulation. It also provides datagram +// based network I/O methods specific to the IPv6 and higher layer +// protocols such as OSPF, GRE, and UDP. +type PacketConn struct { + genericOpt + dgramOpt + payloadHandler +} + +type dgramOpt struct { + net.PacketConn +} + +func (c *dgramOpt) ok() bool { return c != nil && c.PacketConn != nil } + +// SetControlMessage allows to receive the per packet basis IP-level +// socket options. +func (c *PacketConn) SetControlMessage(cf ControlFlags, on bool) error { + if !c.payloadHandler.ok() { + return syscall.EINVAL + } + fd, err := c.payloadHandler.sysfd() + if err != nil { + return err + } + return setControlMessage(fd, &c.payloadHandler.rawOpt, cf, on) +} + +// SetDeadline sets the read and write deadlines associated with the +// endpoint. +func (c *PacketConn) SetDeadline(t time.Time) error { + if !c.payloadHandler.ok() { + return syscall.EINVAL + } + return c.payloadHandler.SetDeadline(t) +} + +// SetReadDeadline sets the read deadline associated with the +// endpoint. +func (c *PacketConn) SetReadDeadline(t time.Time) error { + if !c.payloadHandler.ok() { + return syscall.EINVAL + } + return c.payloadHandler.SetReadDeadline(t) +} + +// SetWriteDeadline sets the write deadline associated with the +// endpoint. +func (c *PacketConn) SetWriteDeadline(t time.Time) error { + if !c.payloadHandler.ok() { + return syscall.EINVAL + } + return c.payloadHandler.SetWriteDeadline(t) +} + +// Close closes the endpoint. +func (c *PacketConn) Close() error { + if !c.payloadHandler.ok() { + return syscall.EINVAL + } + return c.payloadHandler.Close() +} + +// NewPacketConn returns a new PacketConn using c as its underlying +// transport. +func NewPacketConn(c net.PacketConn) *PacketConn { + return &PacketConn{ + genericOpt: genericOpt{Conn: c.(net.Conn)}, + dgramOpt: dgramOpt{PacketConn: c}, + payloadHandler: payloadHandler{PacketConn: c}, + } +} diff --git a/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/gen.go b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/gen.go new file mode 100644 index 000000000..5680bac76 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/gen.go @@ -0,0 +1,241 @@ +// 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. + +// +build ignore + +// This program generates internet protocol constatns and tables by +// reading IANA protocol registries. +// +// Usage: +// go run gen.go > iana.go +package main + +import ( + "bytes" + "encoding/xml" + "fmt" + "go/format" + "io" + "net/http" + "os" + "strconv" + "strings" +) + +var registries = []struct { + url string + parse func(io.Writer, io.Reader) error +}{ + { + "http://www.iana.org/assignments/icmpv6-parameters/icmpv6-parameters.xml", + parseICMPv6Parameters, + }, + { + "http://www.iana.org/assignments/protocol-numbers/protocol-numbers.xml", + parseProtocolNumbers, + }, +} + +func main() { + var bb bytes.Buffer + fmt.Fprintf(&bb, "// go run gen.go\n") + fmt.Fprintf(&bb, "// GENERATED BY THE COMMAND ABOVE; DO NOT EDIT\n\n") + fmt.Fprintf(&bb, "package ipv6\n\n") + for _, r := range registries { + resp, err := http.Get(r.url) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + fmt.Fprintf(os.Stderr, "got HTTP status code %v for %v\n", resp.StatusCode, r.url) + os.Exit(1) + } + if err := r.parse(&bb, resp.Body); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + fmt.Fprintf(&bb, "\n") + } + b, err := format.Source(bb.Bytes()) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + os.Stdout.Write(b) +} + +func parseICMPv6Parameters(w io.Writer, r io.Reader) error { + dec := xml.NewDecoder(r) + var icp icmpv6Parameters + if err := dec.Decode(&icp); err != nil { + return err + } + prs := icp.escape() + fmt.Fprintf(w, "// %s, Updated: %s\n", icp.Title, icp.Updated) + fmt.Fprintf(w, "const (\n") + for _, pr := range prs { + if pr.Name == "" { + continue + } + fmt.Fprintf(w, "ICMPType%s ICMPType = %d", pr.Name, pr.Value) + fmt.Fprintf(w, "// %s\n", pr.OrigName) + } + fmt.Fprintf(w, ")\n\n") + fmt.Fprintf(w, "// %s, Updated: %s\n", icp.Title, icp.Updated) + fmt.Fprintf(w, "var icmpTypes = map[ICMPType]string{\n") + for _, pr := range prs { + if pr.Name == "" { + continue + } + fmt.Fprintf(w, "%d: %q,\n", pr.Value, strings.ToLower(pr.OrigName)) + } + fmt.Fprintf(w, "}\n") + return nil +} + +type icmpv6Parameters struct { + XMLName xml.Name `xml:"registry"` + Title string `xml:"title"` + Updated string `xml:"updated"` + Registries []struct { + Title string `xml:"title"` + Records []struct { + Value string `xml:"value"` + Name string `xml:"name"` + } `xml:"record"` + } `xml:"registry"` +} + +type canonICMPv6ParamRecord struct { + OrigName string + Name string + Value int +} + +func (icp *icmpv6Parameters) escape() []canonICMPv6ParamRecord { + id := -1 + for i, r := range icp.Registries { + if strings.Contains(r.Title, "Type") || strings.Contains(r.Title, "type") { + id = i + break + } + } + if id < 0 { + return nil + } + prs := make([]canonICMPv6ParamRecord, len(icp.Registries[id].Records)) + sr := strings.NewReplacer( + "Messages", "", + "Message", "", + "ICMP", "", + "+", "P", + "-", "", + "/", "", + ".", "", + " ", "", + ) + for i, pr := range icp.Registries[id].Records { + if strings.Contains(pr.Name, "Reserved") || + strings.Contains(pr.Name, "Unassigned") || + strings.Contains(pr.Name, "Deprecated") || + strings.Contains(pr.Name, "Experiment") || + strings.Contains(pr.Name, "experiment") { + continue + } + ss := strings.Split(pr.Name, "\n") + if len(ss) > 1 { + prs[i].Name = strings.Join(ss, " ") + } else { + prs[i].Name = ss[0] + } + s := strings.TrimSpace(prs[i].Name) + prs[i].OrigName = s + prs[i].Name = sr.Replace(s) + prs[i].Value, _ = strconv.Atoi(pr.Value) + } + return prs +} + +func parseProtocolNumbers(w io.Writer, r io.Reader) error { + dec := xml.NewDecoder(r) + var pn protocolNumbers + if err := dec.Decode(&pn); err != nil { + return err + } + prs := pn.escape() + fmt.Fprintf(w, "// %s, Updated: %s\n", pn.Title, pn.Updated) + fmt.Fprintf(w, "const (\n") + for _, pr := range prs { + if pr.Name == "" { + continue + } + fmt.Fprintf(w, "ianaProtocol%s = %d", pr.Name, pr.Value) + s := pr.Descr + if s == "" { + s = pr.OrigName + } + fmt.Fprintf(w, "// %s\n", s) + } + fmt.Fprintf(w, ")\n") + return nil +} + +type protocolNumbers struct { + XMLName xml.Name `xml:"registry"` + Title string `xml:"title"` + Updated string `xml:"updated"` + RegTitle string `xml:"registry>title"` + Note string `xml:"registry>note"` + Records []struct { + Value string `xml:"value"` + Name string `xml:"name"` + Descr string `xml:"description"` + } `xml:"registry>record"` +} + +type canonProtocolRecord struct { + OrigName string + Name string + Descr string + Value int +} + +func (pn *protocolNumbers) escape() []canonProtocolRecord { + prs := make([]canonProtocolRecord, len(pn.Records)) + sr := strings.NewReplacer( + "-in-", "in", + "-within-", "within", + "-over-", "over", + "+", "P", + "-", "", + "/", "", + ".", "", + " ", "", + ) + for i, pr := range pn.Records { + prs[i].OrigName = pr.Name + s := strings.TrimSpace(pr.Name) + switch pr.Name { + case "ISIS over IPv4": + prs[i].Name = "ISIS" + case "manet": + prs[i].Name = "MANET" + default: + prs[i].Name = sr.Replace(s) + } + ss := strings.Split(pr.Descr, "\n") + for i := range ss { + ss[i] = strings.TrimSpace(ss[i]) + } + if len(ss) > 1 { + prs[i].Descr = strings.Join(ss, " ") + } else { + prs[i].Descr = ss[0] + } + prs[i].Value, _ = strconv.Atoi(pr.Value) + } + return prs +} diff --git a/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/genericopt_plan9.go b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/genericopt_plan9.go new file mode 100644 index 000000000..6108443f5 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/genericopt_plan9.go @@ -0,0 +1,34 @@ +// 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 ipv6 + +import "syscall" + +// TrafficClass returns the traffic class field value for outgoing +// packets. +func (c *genericOpt) TrafficClass() (int, error) { + // TODO(mikio): Implement this + return 0, syscall.EPLAN9 +} + +// SetTrafficClass sets the traffic class field value for future +// outgoing packets. +func (c *genericOpt) SetTrafficClass(tclass int) error { + // TODO(mikio): Implement this + return syscall.EPLAN9 +} + +// HopLimit returns the hop limit field value for outgoing packets. +func (c *genericOpt) HopLimit() (int, error) { + // TODO(mikio): Implement this + return 0, syscall.EPLAN9 +} + +// SetHopLimit sets the hop limit field value for future outgoing +// packets. +func (c *genericOpt) SetHopLimit(hoplim int) error { + // TODO(mikio): Implement this + return syscall.EPLAN9 +} diff --git a/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/genericopt_posix.go b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/genericopt_posix.go new file mode 100644 index 000000000..a3a9af9a4 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/genericopt_posix.go @@ -0,0 +1,60 @@ +// 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. + +// +build darwin freebsd linux netbsd openbsd windows + +package ipv6 + +import "syscall" + +// TrafficClass returns the traffic class field value for outgoing +// packets. +func (c *genericOpt) TrafficClass() (int, error) { + if !c.ok() { + return 0, syscall.EINVAL + } + fd, err := c.sysfd() + if err != nil { + return 0, err + } + return ipv6TrafficClass(fd) +} + +// SetTrafficClass sets the traffic class field value for future +// outgoing packets. +func (c *genericOpt) SetTrafficClass(tclass int) error { + if !c.ok() { + return syscall.EINVAL + } + fd, err := c.sysfd() + if err != nil { + return err + } + return setIPv6TrafficClass(fd, tclass) +} + +// HopLimit returns the hop limit field value for outgoing packets. +func (c *genericOpt) HopLimit() (int, error) { + if !c.ok() { + return 0, syscall.EINVAL + } + fd, err := c.sysfd() + if err != nil { + return 0, err + } + return ipv6HopLimit(fd) +} + +// SetHopLimit sets the hop limit field value for future outgoing +// packets. +func (c *genericOpt) SetHopLimit(hoplim int) error { + if !c.ok() { + return syscall.EINVAL + } + fd, err := c.sysfd() + if err != nil { + return err + } + return setIPv6HopLimit(fd, hoplim) +} diff --git a/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/gentest.go b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/gentest.go new file mode 100644 index 000000000..606930f63 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/gentest.go @@ -0,0 +1,195 @@ +// 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. + +// +build ignore + +// This program generates internet protocol constants by reading IANA +// protocol registries. +// +// Usage: +// go run gentest.go > iana_test.go +package main + +import ( + "bytes" + "encoding/xml" + "fmt" + "go/format" + "io" + "net/http" + "os" + "strconv" + "strings" +) + +var registries = []struct { + url string + parse func(io.Writer, io.Reader) error +}{ + { + "http://www.iana.org/assignments/dscp-registry/dscp-registry.xml", + parseDSCPRegistry, + }, + { + "http://www.iana.org/assignments/ipv4-tos-byte/ipv4-tos-byte.xml", + parseTOSTCByte, + }, +} + +func main() { + var bb bytes.Buffer + fmt.Fprintf(&bb, "// go run gentest.go\n") + fmt.Fprintf(&bb, "// GENERATED BY THE COMMAND ABOVE; DO NOT EDIT\n\n") + fmt.Fprintf(&bb, "package ipv6_test\n\n") + for _, r := range registries { + resp, err := http.Get(r.url) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + fmt.Fprintf(os.Stderr, "got HTTP status code %v for %v\n", resp.StatusCode, r.url) + os.Exit(1) + } + if err := r.parse(&bb, resp.Body); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + fmt.Fprintf(&bb, "\n") + } + b, err := format.Source(bb.Bytes()) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + os.Stdout.Write(b) +} + +func parseDSCPRegistry(w io.Writer, r io.Reader) error { + dec := xml.NewDecoder(r) + var dr dscpRegistry + if err := dec.Decode(&dr); err != nil { + return err + } + drs := dr.escape() + fmt.Fprintf(w, "// %s, Updated: %s\n", dr.Title, dr.Updated) + fmt.Fprintf(w, "const (\n") + for _, dr := range drs { + fmt.Fprintf(w, "DiffServ%s = %#x", dr.Name, dr.Value) + fmt.Fprintf(w, "// %s\n", dr.OrigName) + } + fmt.Fprintf(w, ")\n") + return nil +} + +type dscpRegistry struct { + XMLName xml.Name `xml:"registry"` + Title string `xml:"title"` + Updated string `xml:"updated"` + Note string `xml:"note"` + RegTitle string `xml:"registry>title"` + PoolRecords []struct { + Name string `xml:"name"` + Space string `xml:"space"` + } `xml:"registry>record"` + Records []struct { + Name string `xml:"name"` + Space string `xml:"space"` + } `xml:"registry>registry>record"` +} + +type canonDSCPRecord struct { + OrigName string + Name string + Value int +} + +func (drr *dscpRegistry) escape() []canonDSCPRecord { + drs := make([]canonDSCPRecord, len(drr.Records)) + sr := strings.NewReplacer( + "+", "", + "-", "", + "/", "", + ".", "", + " ", "", + ) + for i, dr := range drr.Records { + s := strings.TrimSpace(dr.Name) + drs[i].OrigName = s + drs[i].Name = sr.Replace(s) + n, err := strconv.ParseUint(dr.Space, 2, 8) + if err != nil { + continue + } + drs[i].Value = int(n) << 2 + } + return drs +} + +func parseTOSTCByte(w io.Writer, r io.Reader) error { + dec := xml.NewDecoder(r) + var ttb tosTCByte + if err := dec.Decode(&ttb); err != nil { + return err + } + trs := ttb.escape() + fmt.Fprintf(w, "// %s, Updated: %s\n", ttb.Title, ttb.Updated) + fmt.Fprintf(w, "const (\n") + for _, tr := range trs { + fmt.Fprintf(w, "%s = %#x", tr.Keyword, tr.Value) + fmt.Fprintf(w, "// %s\n", tr.OrigKeyword) + } + fmt.Fprintf(w, ")\n") + return nil +} + +type tosTCByte struct { + XMLName xml.Name `xml:"registry"` + Title string `xml:"title"` + Updated string `xml:"updated"` + Note string `xml:"note"` + RegTitle string `xml:"registry>title"` + Records []struct { + Binary string `xml:"binary"` + Keyword string `xml:"keyword"` + } `xml:"registry>record"` +} + +type canonTOSTCByteRecord struct { + OrigKeyword string + Keyword string + Value int +} + +func (ttb *tosTCByte) escape() []canonTOSTCByteRecord { + trs := make([]canonTOSTCByteRecord, len(ttb.Records)) + sr := strings.NewReplacer( + "Capable", "", + "(", "", + ")", "", + "+", "", + "-", "", + "/", "", + ".", "", + " ", "", + ) + for i, tr := range ttb.Records { + s := strings.TrimSpace(tr.Keyword) + trs[i].OrigKeyword = s + ss := strings.Split(s, " ") + if len(ss) > 1 { + trs[i].Keyword = strings.Join(ss[1:], " ") + } else { + trs[i].Keyword = ss[0] + } + trs[i].Keyword = sr.Replace(trs[i].Keyword) + n, err := strconv.ParseUint(tr.Binary, 2, 8) + if err != nil { + continue + } + trs[i].Value = int(n) + } + return trs +} diff --git a/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/helper.go b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/helper.go new file mode 100644 index 000000000..ec87a0f73 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/helper.go @@ -0,0 +1,28 @@ +// 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 ipv6 + +import "net" + +func boolint(b bool) int { + if b { + return 1 + } + return 0 +} + +func netAddrToIP16(a net.Addr) net.IP { + switch v := a.(type) { + case *net.UDPAddr: + if ip := v.IP.To16(); ip != nil && ip.To4() == nil { + return ip + } + case *net.IPAddr: + if ip := v.IP.To16(); ip != nil && ip.To4() == nil { + return ip + } + } + return nil +} diff --git a/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/helper_plan9.go b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/helper_plan9.go new file mode 100644 index 000000000..9f12a3a10 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/helper_plan9.go @@ -0,0 +1,22 @@ +// 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 ipv6 + +import "syscall" + +func (c *genericOpt) sysfd() (int, error) { + // TODO(mikio): Implement this + return 0, syscall.EPLAN9 +} + +func (c *dgramOpt) sysfd() (int, error) { + // TODO(mikio): Implement this + return 0, syscall.EPLAN9 +} + +func (c *payloadHandler) sysfd() (int, error) { + // TODO(mikio): Implement this + return 0, syscall.EPLAN9 +} diff --git a/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/helper_unix.go b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/helper_unix.go new file mode 100644 index 000000000..6ad8db453 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/helper_unix.go @@ -0,0 +1,46 @@ +// 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. + +// +build darwin freebsd linux netbsd openbsd + +package ipv6 + +import ( + "net" + "reflect" +) + +func (c *genericOpt) sysfd() (int, error) { + switch p := c.Conn.(type) { + case *net.TCPConn, *net.UDPConn, *net.IPConn: + return sysfd(p) + } + return 0, errInvalidConnType +} + +func (c *dgramOpt) sysfd() (int, error) { + switch p := c.PacketConn.(type) { + case *net.UDPConn, *net.IPConn: + return sysfd(p.(net.Conn)) + } + return 0, errInvalidConnType +} + +func (c *payloadHandler) sysfd() (int, error) { + return sysfd(c.PacketConn.(net.Conn)) +} + +func sysfd(c net.Conn) (int, error) { + cv := reflect.ValueOf(c) + switch ce := cv.Elem(); ce.Kind() { + case reflect.Struct: + nfd := ce.FieldByName("conn").FieldByName("fd") + switch fe := nfd.Elem(); fe.Kind() { + case reflect.Struct: + fd := fe.FieldByName("sysfd") + return int(fd.Int()), nil + } + } + return 0, errInvalidConnType +} diff --git a/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/helper_windows.go b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/helper_windows.go new file mode 100644 index 000000000..28c401b53 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/helper_windows.go @@ -0,0 +1,45 @@ +// 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 ipv6 + +import ( + "net" + "reflect" + "syscall" +) + +func (c *genericOpt) sysfd() (syscall.Handle, error) { + switch p := c.Conn.(type) { + case *net.TCPConn, *net.UDPConn, *net.IPConn: + return sysfd(p) + } + return syscall.InvalidHandle, errInvalidConnType +} + +func (c *dgramOpt) sysfd() (syscall.Handle, error) { + switch p := c.PacketConn.(type) { + case *net.UDPConn, *net.IPConn: + return sysfd(p.(net.Conn)) + } + return syscall.InvalidHandle, errInvalidConnType +} + +func (c *payloadHandler) sysfd() (syscall.Handle, error) { + return sysfd(c.PacketConn.(net.Conn)) +} + +func sysfd(c net.Conn) (syscall.Handle, error) { + cv := reflect.ValueOf(c) + switch ce := cv.Elem(); ce.Kind() { + case reflect.Struct: + netfd := ce.FieldByName("conn").FieldByName("fd") + switch fe := netfd.Elem(); fe.Kind() { + case reflect.Struct: + fd := fe.FieldByName("sysfd") + return syscall.Handle(fd.Uint()), nil + } + } + return syscall.InvalidHandle, errInvalidConnType +} diff --git a/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/iana.go b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/iana.go new file mode 100644 index 000000000..429087c5f --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/iana.go @@ -0,0 +1,224 @@ +// go run gen.go +// GENERATED BY THE COMMAND ABOVE; DO NOT EDIT + +package ipv6 + +// Internet Control Message Protocol version 6 (ICMPv6) Parameters, Updated: 2013-07-03 +const ( + ICMPTypeDestinationUnreachable ICMPType = 1 // Destination Unreachable + ICMPTypePacketTooBig ICMPType = 2 // Packet Too Big + ICMPTypeTimeExceeded ICMPType = 3 // Time Exceeded + ICMPTypeParameterProblem ICMPType = 4 // Parameter Problem + ICMPTypeEchoRequest ICMPType = 128 // Echo Request + ICMPTypeEchoReply ICMPType = 129 // Echo Reply + ICMPTypeMulticastListenerQuery ICMPType = 130 // Multicast Listener Query + ICMPTypeMulticastListenerReport ICMPType = 131 // Multicast Listener Report + ICMPTypeMulticastListenerDone ICMPType = 132 // Multicast Listener Done + ICMPTypeRouterSolicitation ICMPType = 133 // Router Solicitation + ICMPTypeRouterAdvertisement ICMPType = 134 // Router Advertisement + ICMPTypeNeighborSolicitation ICMPType = 135 // Neighbor Solicitation + ICMPTypeNeighborAdvertisement ICMPType = 136 // Neighbor Advertisement + ICMPTypeRedirect ICMPType = 137 // Redirect Message + ICMPTypeRouterRenumbering ICMPType = 138 // Router Renumbering + ICMPTypeNodeInformationQuery ICMPType = 139 // ICMP Node Information Query + ICMPTypeNodeInformationResponse ICMPType = 140 // ICMP Node Information Response + ICMPTypeInverseNeighborDiscoverySolicitation ICMPType = 141 // Inverse Neighbor Discovery Solicitation Message + ICMPTypeInverseNeighborDiscoveryAdvertisement ICMPType = 142 // Inverse Neighbor Discovery Advertisement Message + ICMPTypeVersion2MulticastListenerReport ICMPType = 143 // Version 2 Multicast Listener Report + ICMPTypeHomeAgentAddressDiscoveryRequest ICMPType = 144 // Home Agent Address Discovery Request Message + ICMPTypeHomeAgentAddressDiscoveryReply ICMPType = 145 // Home Agent Address Discovery Reply Message + ICMPTypeMobilePrefixSolicitation ICMPType = 146 // Mobile Prefix Solicitation + ICMPTypeMobilePrefixAdvertisement ICMPType = 147 // Mobile Prefix Advertisement + ICMPTypeCertificationPathSolicitation ICMPType = 148 // Certification Path Solicitation Message + ICMPTypeCertificationPathAdvertisement ICMPType = 149 // Certification Path Advertisement Message + ICMPTypeMulticastRouterAdvertisement ICMPType = 151 // Multicast Router Advertisement + ICMPTypeMulticastRouterSolicitation ICMPType = 152 // Multicast Router Solicitation + ICMPTypeMulticastRouterTermination ICMPType = 153 // Multicast Router Termination + ICMPTypeFMIPv6 ICMPType = 154 // FMIPv6 Messages + ICMPTypeRPLControl ICMPType = 155 // RPL Control Message + ICMPTypeILNPv6LocatorUpdate ICMPType = 156 // ILNPv6 Locator Update Message + ICMPTypeDuplicateAddressRequest ICMPType = 157 // Duplicate Address Request + ICMPTypeDuplicateAddressConfirmation ICMPType = 158 // Duplicate Address Confirmation +) + +// Internet Control Message Protocol version 6 (ICMPv6) Parameters, Updated: 2013-07-03 +var icmpTypes = map[ICMPType]string{ + 1: "destination unreachable", + 2: "packet too big", + 3: "time exceeded", + 4: "parameter problem", + 128: "echo request", + 129: "echo reply", + 130: "multicast listener query", + 131: "multicast listener report", + 132: "multicast listener done", + 133: "router solicitation", + 134: "router advertisement", + 135: "neighbor solicitation", + 136: "neighbor advertisement", + 137: "redirect message", + 138: "router renumbering", + 139: "icmp node information query", + 140: "icmp node information response", + 141: "inverse neighbor discovery solicitation message", + 142: "inverse neighbor discovery advertisement message", + 143: "version 2 multicast listener report", + 144: "home agent address discovery request message", + 145: "home agent address discovery reply message", + 146: "mobile prefix solicitation", + 147: "mobile prefix advertisement", + 148: "certification path solicitation message", + 149: "certification path advertisement message", + 151: "multicast router advertisement", + 152: "multicast router solicitation", + 153: "multicast router termination", + 154: "fmipv6 messages", + 155: "rpl control message", + 156: "ilnpv6 locator update message", + 157: "duplicate address request", + 158: "duplicate address confirmation", +} + +// Protocol Numbers, Updated: 2013-02-17 +const ( + ianaProtocolHOPOPT = 0 // IPv6 Hop-by-Hop Option + ianaProtocolICMP = 1 // Internet Control Message + ianaProtocolIGMP = 2 // Internet Group Management + ianaProtocolGGP = 3 // Gateway-to-Gateway + ianaProtocolIPv4 = 4 // IPv4 encapsulation + ianaProtocolST = 5 // Stream + ianaProtocolTCP = 6 // Transmission Control + ianaProtocolCBT = 7 // CBT + ianaProtocolEGP = 8 // Exterior Gateway Protocol + ianaProtocolIGP = 9 // any private interior gateway (used by Cisco for their IGRP) + ianaProtocolBBNRCCMON = 10 // BBN RCC Monitoring + ianaProtocolNVPII = 11 // Network Voice Protocol + ianaProtocolPUP = 12 // PUP + ianaProtocolARGUS = 13 // ARGUS + ianaProtocolEMCON = 14 // EMCON + ianaProtocolXNET = 15 // Cross Net Debugger + ianaProtocolCHAOS = 16 // Chaos + ianaProtocolUDP = 17 // User Datagram + ianaProtocolMUX = 18 // Multiplexing + ianaProtocolDCNMEAS = 19 // DCN Measurement Subsystems + ianaProtocolHMP = 20 // Host Monitoring + ianaProtocolPRM = 21 // Packet Radio Measurement + ianaProtocolXNSIDP = 22 // XEROX NS IDP + ianaProtocolTRUNK1 = 23 // Trunk-1 + ianaProtocolTRUNK2 = 24 // Trunk-2 + ianaProtocolLEAF1 = 25 // Leaf-1 + ianaProtocolLEAF2 = 26 // Leaf-2 + ianaProtocolRDP = 27 // Reliable Data Protocol + ianaProtocolIRTP = 28 // Internet Reliable Transaction + ianaProtocolISOTP4 = 29 // ISO Transport Protocol Class 4 + ianaProtocolNETBLT = 30 // Bulk Data Transfer Protocol + ianaProtocolMFENSP = 31 // MFE Network Services Protocol + ianaProtocolMERITINP = 32 // MERIT Internodal Protocol + ianaProtocolDCCP = 33 // Datagram Congestion Control Protocol + ianaProtocol3PC = 34 // Third Party Connect Protocol + ianaProtocolIDPR = 35 // Inter-Domain Policy Routing Protocol + ianaProtocolXTP = 36 // XTP + ianaProtocolDDP = 37 // Datagram Delivery Protocol + ianaProtocolIDPRCMTP = 38 // IDPR Control Message Transport Proto + ianaProtocolTPPP = 39 // TP++ Transport Protocol + ianaProtocolIL = 40 // IL Transport Protocol + ianaProtocolIPv6 = 41 // IPv6 encapsulation + ianaProtocolSDRP = 42 // Source Demand Routing Protocol + ianaProtocolIPv6Route = 43 // Routing Header for IPv6 + ianaProtocolIPv6Frag = 44 // Fragment Header for IPv6 + ianaProtocolIDRP = 45 // Inter-Domain Routing Protocol + ianaProtocolRSVP = 46 // Reservation Protocol + ianaProtocolGRE = 47 // Generic Routing Encapsulation + ianaProtocolDSR = 48 // Dynamic Source Routing Protocol + ianaProtocolBNA = 49 // BNA + ianaProtocolESP = 50 // Encap Security Payload + ianaProtocolAH = 51 // Authentication Header + ianaProtocolINLSP = 52 // Integrated Net Layer Security TUBA + ianaProtocolSWIPE = 53 // IP with Encryption + ianaProtocolNARP = 54 // NBMA Address Resolution Protocol + ianaProtocolMOBILE = 55 // IP Mobility + ianaProtocolTLSP = 56 // Transport Layer Security Protocol using Kryptonet key management + ianaProtocolSKIP = 57 // SKIP + ianaProtocolIPv6ICMP = 58 // ICMP for IPv6 + ianaProtocolIPv6NoNxt = 59 // No Next Header for IPv6 + ianaProtocolIPv6Opts = 60 // Destination Options for IPv6 + ianaProtocolCFTP = 62 // CFTP + ianaProtocolSATEXPAK = 64 // SATNET and Backroom EXPAK + ianaProtocolKRYPTOLAN = 65 // Kryptolan + ianaProtocolRVD = 66 // MIT Remote Virtual Disk Protocol + ianaProtocolIPPC = 67 // Internet Pluribus Packet Core + ianaProtocolSATMON = 69 // SATNET Monitoring + ianaProtocolVISA = 70 // VISA Protocol + ianaProtocolIPCV = 71 // Internet Packet Core Utility + ianaProtocolCPNX = 72 // Computer Protocol Network Executive + ianaProtocolCPHB = 73 // Computer Protocol Heart Beat + ianaProtocolWSN = 74 // Wang Span Network + ianaProtocolPVP = 75 // Packet Video Protocol + ianaProtocolBRSATMON = 76 // Backroom SATNET Monitoring + ianaProtocolSUNND = 77 // SUN ND PROTOCOL-Temporary + ianaProtocolWBMON = 78 // WIDEBAND Monitoring + ianaProtocolWBEXPAK = 79 // WIDEBAND EXPAK + ianaProtocolISOIP = 80 // ISO Internet Protocol + ianaProtocolVMTP = 81 // VMTP + ianaProtocolSECUREVMTP = 82 // SECURE-VMTP + ianaProtocolVINES = 83 // VINES + ianaProtocolTTP = 84 // TTP + ianaProtocolIPTM = 84 // Protocol Internet Protocol Traffic Manager + ianaProtocolNSFNETIGP = 85 // NSFNET-IGP + ianaProtocolDGP = 86 // Dissimilar Gateway Protocol + ianaProtocolTCF = 87 // TCF + ianaProtocolEIGRP = 88 // EIGRP + ianaProtocolOSPFIGP = 89 // OSPFIGP + ianaProtocolSpriteRPC = 90 // Sprite RPC Protocol + ianaProtocolLARP = 91 // Locus Address Resolution Protocol + ianaProtocolMTP = 92 // Multicast Transport Protocol + ianaProtocolAX25 = 93 // AX.25 Frames + ianaProtocolIPIP = 94 // IP-within-IP Encapsulation Protocol + ianaProtocolMICP = 95 // Mobile Internetworking Control Pro. + ianaProtocolSCCSP = 96 // Semaphore Communications Sec. Pro. + ianaProtocolETHERIP = 97 // Ethernet-within-IP Encapsulation + ianaProtocolENCAP = 98 // Encapsulation Header + ianaProtocolGMTP = 100 // GMTP + ianaProtocolIFMP = 101 // Ipsilon Flow Management Protocol + ianaProtocolPNNI = 102 // PNNI over IP + ianaProtocolPIM = 103 // Protocol Independent Multicast + ianaProtocolARIS = 104 // ARIS + ianaProtocolSCPS = 105 // SCPS + ianaProtocolQNX = 106 // QNX + ianaProtocolAN = 107 // Active Networks + ianaProtocolIPComp = 108 // IP Payload Compression Protocol + ianaProtocolSNP = 109 // Sitara Networks Protocol + ianaProtocolCompaqPeer = 110 // Compaq Peer Protocol + ianaProtocolIPXinIP = 111 // IPX in IP + ianaProtocolVRRP = 112 // Virtual Router Redundancy Protocol + ianaProtocolPGM = 113 // PGM Reliable Transport Protocol + ianaProtocolL2TP = 115 // Layer Two Tunneling Protocol + ianaProtocolDDX = 116 // D-II Data Exchange (DDX) + ianaProtocolIATP = 117 // Interactive Agent Transfer Protocol + ianaProtocolSTP = 118 // Schedule Transfer Protocol + ianaProtocolSRP = 119 // SpectraLink Radio Protocol + ianaProtocolUTI = 120 // UTI + ianaProtocolSMP = 121 // Simple Message Protocol + ianaProtocolSM = 122 // SM + ianaProtocolPTP = 123 // Performance Transparency Protocol + ianaProtocolISIS = 124 // ISIS over IPv4 + ianaProtocolFIRE = 125 // FIRE + ianaProtocolCRTP = 126 // Combat Radio Transport Protocol + ianaProtocolCRUDP = 127 // Combat Radio User Datagram + ianaProtocolSSCOPMCE = 128 // SSCOPMCE + ianaProtocolIPLT = 129 // IPLT + ianaProtocolSPS = 130 // Secure Packet Shield + ianaProtocolPIPE = 131 // Private IP Encapsulation within IP + ianaProtocolSCTP = 132 // Stream Control Transmission Protocol + ianaProtocolFC = 133 // Fibre Channel + ianaProtocolRSVPE2EIGNORE = 134 // RSVP-E2E-IGNORE + ianaProtocolMobilityHeader = 135 // Mobility Header + ianaProtocolUDPLite = 136 // UDPLite + ianaProtocolMPLSinIP = 137 // MPLS-in-IP + ianaProtocolMANET = 138 // MANET Protocols + ianaProtocolHIP = 139 // Host Identity Protocol + ianaProtocolShim6 = 140 // Shim6 Protocol + ianaProtocolWESP = 141 // Wrapped Encapsulating Security Payload + ianaProtocolROHC = 142 // Robust Header Compression + ianaProtocolReserved = 255 // Reserved +) diff --git a/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/iana_test.go b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/iana_test.go new file mode 100644 index 000000000..03e8bfe5a --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/iana_test.go @@ -0,0 +1,38 @@ +// go run gentest.go +// GENERATED BY THE COMMAND ABOVE; DO NOT EDIT + +package ipv6_test + +// Differentiated Services Field Codepoints (DSCP), Updated: 2013-06-25 +const ( + DiffServCS0 = 0x0 // CS0 + DiffServCS1 = 0x20 // CS1 + DiffServCS2 = 0x40 // CS2 + DiffServCS3 = 0x60 // CS3 + DiffServCS4 = 0x80 // CS4 + DiffServCS5 = 0xa0 // CS5 + DiffServCS6 = 0xc0 // CS6 + DiffServCS7 = 0xe0 // CS7 + DiffServAF11 = 0x28 // AF11 + DiffServAF12 = 0x30 // AF12 + DiffServAF13 = 0x38 // AF13 + DiffServAF21 = 0x48 // AF21 + DiffServAF22 = 0x50 // AF22 + DiffServAF23 = 0x58 // AF23 + DiffServAF31 = 0x68 // AF31 + DiffServAF32 = 0x70 // AF32 + DiffServAF33 = 0x78 // AF33 + DiffServAF41 = 0x88 // AF41 + DiffServAF42 = 0x90 // AF42 + DiffServAF43 = 0x98 // AF43 + DiffServEFPHB = 0xb8 // EF PHB + DiffServVOICEADMIT = 0xb0 // VOICE-ADMIT +) + +// IPv4 TOS Byte and IPv6 Traffic Class Octet, Updated: 2001-09-06 +const ( + NotECNTransport = 0x0 // Not-ECT (Not ECN-Capable Transport) + ECNTransport1 = 0x1 // ECT(1) (ECN-Capable Transport(1)) + ECNTransport0 = 0x2 // ECT(0) (ECN-Capable Transport(0)) + CongestionExperienced = 0x3 // CE (Congestion Experienced) +) diff --git a/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/icmp.go b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/icmp.go new file mode 100644 index 000000000..9fb6a483c --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/icmp.go @@ -0,0 +1,46 @@ +// 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 ipv6 + +import "sync" + +// An ICMPType represents a type of ICMP message. +type ICMPType int + +func (typ ICMPType) String() string { + s, ok := icmpTypes[typ] + if !ok { + return "" + } + return s +} + +// An ICMPFilter represents an ICMP message filter for incoming +// packets. +type ICMPFilter struct { + mu sync.RWMutex + rawICMPFilter +} + +// Set sets the ICMP type and filter action to the filter. +func (f *ICMPFilter) Set(typ ICMPType, block bool) { + f.mu.Lock() + defer f.mu.Unlock() + f.set(typ, block) +} + +// SetAll sets the filter action to the filter. +func (f *ICMPFilter) SetAll(block bool) { + f.mu.Lock() + defer f.mu.Unlock() + f.setAll(block) +} + +// WillBlock reports whether the ICMP type will be blocked. +func (f *ICMPFilter) WillBlock(typ ICMPType) bool { + f.mu.RLock() + defer f.mu.RUnlock() + return f.willBlock(typ) +} diff --git a/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/icmp_bsd.go b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/icmp_bsd.go new file mode 100644 index 000000000..fd5f83ef9 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/icmp_bsd.go @@ -0,0 +1,35 @@ +// 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. + +// +build darwin freebsd netbsd openbsd + +package ipv6 + +import "syscall" + +type rawICMPFilter struct { + syscall.ICMPv6Filter +} + +func (f *rawICMPFilter) set(typ ICMPType, block bool) { + if block { + f.Filt[typ>>5] &^= 1 << (uint32(typ) & 31) + } else { + f.Filt[typ>>5] |= 1 << (uint32(typ) & 31) + } +} + +func (f *rawICMPFilter) setAll(block bool) { + for i := range f.Filt { + if block { + f.Filt[i] = 0 + } else { + f.Filt[i] = 1<<32 - 1 + } + } +} + +func (f *rawICMPFilter) willBlock(typ ICMPType) bool { + return f.Filt[typ>>5]&(1<<(uint32(typ)&31)) == 0 +} diff --git a/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/icmp_linux.go b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/icmp_linux.go new file mode 100644 index 000000000..0a70f5f7c --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/icmp_linux.go @@ -0,0 +1,33 @@ +// 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 ipv6 + +import "syscall" + +type rawICMPFilter struct { + syscall.ICMPv6Filter +} + +func (f *rawICMPFilter) set(typ ICMPType, block bool) { + if block { + f.Data[typ>>5] |= 1 << (uint32(typ) & 31) + } else { + f.Data[typ>>5] &^= 1 << (uint32(typ) & 31) + } +} + +func (f *rawICMPFilter) setAll(block bool) { + for i := range f.Data { + if block { + f.Data[i] = 1<<32 - 1 + } else { + f.Data[i] = 0 + } + } +} + +func (f *rawICMPFilter) willBlock(typ ICMPType) bool { + return f.Data[typ>>5]&(1<<(uint32(typ)&31)) != 0 +} diff --git a/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/icmp_plan9.go b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/icmp_plan9.go new file mode 100644 index 000000000..b97c8280b --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/icmp_plan9.go @@ -0,0 +1,22 @@ +// 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 ipv6 + +type rawICMPFilter struct { + // TODO(mikio): Implement this +} + +func (f *rawICMPFilter) set(typ ICMPType, block bool) { + // TODO(mikio): Implement this +} + +func (f *rawICMPFilter) setAll(block bool) { + // TODO(mikio): Implement this +} + +func (f *rawICMPFilter) willBlock(typ ICMPType) bool { + // TODO(mikio): Implement this + return false +} diff --git a/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/icmp_test.go b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/icmp_test.go new file mode 100644 index 000000000..a7833dd16 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/icmp_test.go @@ -0,0 +1,84 @@ +// 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 ipv6_test + +import ( + "code.google.com/p/go.net/ipv6" + "net" + "os" + "reflect" + "runtime" + "sync" + "testing" +) + +func TestICMPFilter(t *testing.T) { + switch runtime.GOOS { + case "plan9", "windows": + t.Skipf("not supported on %q", runtime.GOOS) + } + + var f ipv6.ICMPFilter + for _, toggle := range []bool{false, true} { + f.SetAll(toggle) + var wg sync.WaitGroup + for _, typ := range []ipv6.ICMPType{ + ipv6.ICMPTypeDestinationUnreachable, + ipv6.ICMPTypeEchoReply, + ipv6.ICMPTypeNeighborSolicitation, + ipv6.ICMPTypeDuplicateAddressConfirmation, + } { + wg.Add(1) + go func(typ ipv6.ICMPType) { + defer wg.Done() + f.Set(typ, false) + if f.WillBlock(typ) { + t.Errorf("ipv6.ICMPFilter.Set(%v, false) failed", typ) + } + f.Set(typ, true) + if !f.WillBlock(typ) { + t.Errorf("ipv6.ICMPFilter.Set(%v, true) failed", typ) + } + }(typ) + } + wg.Wait() + } +} + +func TestSetICMPFilter(t *testing.T) { + switch runtime.GOOS { + case "plan9", "windows": + t.Skipf("not supported on %q", runtime.GOOS) + } + if !supportsIPv6 { + t.Skip("ipv6 is not supported") + } + if os.Getuid() != 0 { + t.Skip("must be root") + } + + c, err := net.ListenPacket("ip6:ipv6-icmp", "::1") + if err != nil { + t.Fatalf("net.ListenPacket failed: %v", err) + } + defer c.Close() + + p := ipv6.NewPacketConn(c) + + var f ipv6.ICMPFilter + f.SetAll(true) + f.Set(ipv6.ICMPTypeEchoRequest, false) + f.Set(ipv6.ICMPTypeEchoReply, false) + if err := p.SetICMPFilter(&f); err != nil { + t.Fatalf("ipv6.PacketConn.SetICMPFilter failed: %v", err) + } + kf, err := p.ICMPFilter() + if err != nil { + t.Fatalf("ipv6.PacketConn.ICMPFilter failed: %v", err) + } + if !reflect.DeepEqual(kf, &f) { + t.Fatalf("got unexpected filter %#v; expected %#v", kf, f) + } +} diff --git a/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/icmp_windows.go b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/icmp_windows.go new file mode 100644 index 000000000..b97c8280b --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/icmp_windows.go @@ -0,0 +1,22 @@ +// 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 ipv6 + +type rawICMPFilter struct { + // TODO(mikio): Implement this +} + +func (f *rawICMPFilter) set(typ ICMPType, block bool) { + // TODO(mikio): Implement this +} + +func (f *rawICMPFilter) setAll(block bool) { + // TODO(mikio): Implement this +} + +func (f *rawICMPFilter) willBlock(typ ICMPType) bool { + // TODO(mikio): Implement this + return false +} diff --git a/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/mockicmp_test.go b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/mockicmp_test.go new file mode 100644 index 000000000..e453a9c54 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/mockicmp_test.go @@ -0,0 +1,112 @@ +// 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 ipv6_test + +import ( + "code.google.com/p/go.net/ipv6" + "errors" +) + +// icmpMessage represents an ICMP message. +type icmpMessage struct { + Type ipv6.ICMPType // type + Code int // code + Checksum int // checksum + Body icmpMessageBody // body +} + +// icmpMessageBody represents an ICMP message body. +type icmpMessageBody interface { + Len() int + Marshal() ([]byte, error) +} + +// Marshal returns the binary enconding of the ICMP echo request or +// reply message m. +func (m *icmpMessage) Marshal() ([]byte, error) { + b := []byte{byte(m.Type), byte(m.Code), 0, 0} + if m.Body != nil && m.Body.Len() != 0 { + mb, err := m.Body.Marshal() + if err != nil { + return nil, err + } + b = append(b, mb...) + } + switch m.Type { + case ipv6.ICMPTypeEchoRequest, ipv6.ICMPTypeEchoReply: + return b, nil + } + csumcv := len(b) - 1 // checksum coverage + s := uint32(0) + for i := 0; i < csumcv; i += 2 { + s += uint32(b[i+1])<<8 | uint32(b[i]) + } + if csumcv&1 == 0 { + s += uint32(b[csumcv]) + } + s = s>>16 + s&0xffff + s = s + s>>16 + // Place checksum back in header; using ^= avoids the + // assumption the checksum bytes are zero. + b[2] ^= byte(^s) + b[3] ^= byte(^s >> 8) + return b, nil +} + +// parseICMPMessage parses b as an ICMP message. +func parseICMPMessage(b []byte) (*icmpMessage, error) { + msglen := len(b) + if msglen < 4 { + return nil, errors.New("message too short") + } + m := &icmpMessage{Type: ipv6.ICMPType(b[0]), Code: int(b[1]), Checksum: int(b[2])<<8 | int(b[3])} + if msglen > 4 { + var err error + switch m.Type { + case ipv6.ICMPTypeEchoRequest, ipv6.ICMPTypeEchoReply: + m.Body, err = parseICMPEcho(b[4:]) + if err != nil { + return nil, err + } + } + } + return m, nil +} + +// imcpEcho represenets an ICMP echo request or reply message body. +type icmpEcho struct { + ID int // identifier + Seq int // sequence number + Data []byte // data +} + +func (p *icmpEcho) Len() int { + if p == nil { + return 0 + } + return 4 + len(p.Data) +} + +// Marshal returns the binary enconding of the ICMP echo request or +// reply message body p. +func (p *icmpEcho) Marshal() ([]byte, error) { + b := make([]byte, 4+len(p.Data)) + b[0], b[1] = byte(p.ID>>8), byte(p.ID) + b[2], b[3] = byte(p.Seq>>8), byte(p.Seq) + copy(b[4:], p.Data) + return b, nil +} + +// parseICMPEcho parses b as an ICMP echo request or reply message +// body. +func parseICMPEcho(b []byte) (*icmpEcho, error) { + bodylen := len(b) + p := &icmpEcho{ID: int(b[0])<<8 | int(b[1]), Seq: int(b[2])<<8 | int(b[3])} + if bodylen > 4 { + p.Data = make([]byte, bodylen-4) + copy(p.Data, b[4:]) + } + return p, nil +} diff --git a/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/mocktransponder_test.go b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/mocktransponder_test.go new file mode 100644 index 000000000..2da546412 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/mocktransponder_test.go @@ -0,0 +1,110 @@ +// 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 ipv6_test + +import ( + "net" + "testing" +) + +func isLinkLocalUnicast(ip net.IP) bool { + return ip.To4() == nil && ip.To16() != nil && ip.IsLinkLocalUnicast() +} + +func loopbackInterface() *net.Interface { + ift, err := net.Interfaces() + if err != nil { + return nil + } + for _, ifi := range ift { + if ifi.Flags&net.FlagLoopback == 0 || ifi.Flags&net.FlagUp == 0 { + continue + } + ifat, err := ifi.Addrs() + if err != nil { + continue + } + for _, ifa := range ifat { + switch ifa := ifa.(type) { + case *net.IPAddr: + if isLinkLocalUnicast(ifa.IP) { + return &ifi + } + case *net.IPNet: + if isLinkLocalUnicast(ifa.IP) { + return &ifi + } + } + } + } + return nil +} + +func isMulticastAvailable(ifi *net.Interface) (net.IP, bool) { + if ifi == nil || ifi.Flags&net.FlagUp == 0 || ifi.Flags&net.FlagMulticast == 0 { + return nil, false + } + ifat, err := ifi.Addrs() + if err != nil { + return nil, false + } + for _, ifa := range ifat { + switch ifa := ifa.(type) { + case *net.IPAddr: + if isLinkLocalUnicast(ifa.IP) { + return ifa.IP, true + } + case *net.IPNet: + if isLinkLocalUnicast(ifa.IP) { + return ifa.IP, true + } + } + } + return nil, false +} + +func connector(t *testing.T, network, addr string, done chan<- bool) { + defer func() { done <- true }() + + c, err := net.Dial(network, addr) + if err != nil { + t.Errorf("net.Dial failed: %v", err) + return + } + c.Close() +} + +func acceptor(t *testing.T, ln net.Listener, done chan<- bool) { + defer func() { done <- true }() + + c, err := ln.Accept() + if err != nil { + t.Errorf("net.Listener.Accept failed: %v", err) + return + } + c.Close() +} + +func transponder(t *testing.T, ln net.Listener, done chan<- bool) { + defer func() { done <- true }() + + c, err := ln.Accept() + if err != nil { + t.Errorf("net.Listener.Accept failed: %v", err) + return + } + defer c.Close() + + b := make([]byte, 128) + n, err := c.Read(b) + if err != nil { + t.Errorf("net.Conn.Read failed: %v", err) + return + } + if _, err := c.Write(b[:n]); err != nil { + t.Errorf("net.Conn.Write failed: %v", err) + return + } +} diff --git a/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/multicast_test.go b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/multicast_test.go new file mode 100644 index 000000000..7267ad4a5 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/multicast_test.go @@ -0,0 +1,161 @@ +// 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 ipv6_test + +import ( + "code.google.com/p/go.net/ipv6" + "net" + "os" + "runtime" + "testing" +) + +func TestPacketConnReadWriteMulticastUDP(t *testing.T) { + switch runtime.GOOS { + case "freebsd": // due to a bug on loopback marking + // See http://www.freebsd.org/cgi/query-pr.cgi?pr=180065. + t.Skipf("not supported on %q", runtime.GOOS) + case "plan9", "windows": + t.Skipf("not supported on %q", runtime.GOOS) + } + if !supportsIPv6 { + t.Skip("ipv6 is not supported") + } + ifi := loopbackInterface() + if ifi == nil { + t.Skipf("not available on %q", runtime.GOOS) + } + + c, err := net.ListenPacket("udp6", "[ff02::114]:0") // see RFC 4727 + if err != nil { + t.Fatalf("net.ListenPacket failed: %v", err) + } + defer c.Close() + + _, port, err := net.SplitHostPort(c.LocalAddr().String()) + if err != nil { + t.Fatalf("net.SplitHostPort failed: %v", err) + } + dst, err := net.ResolveUDPAddr("udp6", "[ff02::114]:"+port) // see RFC 4727 + if err != nil { + t.Fatalf("net.ResolveUDPAddr failed: %v", err) + } + + p := ipv6.NewPacketConn(c) + if err := p.JoinGroup(ifi, dst); err != nil { + t.Fatalf("ipv6.PacketConn.JoinGroup on %v failed: %v", ifi, err) + } + if err := p.SetMulticastInterface(ifi); err != nil { + t.Fatalf("ipv6.PacketConn.SetMulticastInterface failed: %v", err) + } + if err := p.SetMulticastLoopback(true); err != nil { + t.Fatalf("ipv6.PacketConn.SetMulticastLoopback failed: %v", err) + } + + cm := ipv6.ControlMessage{ + TrafficClass: DiffServAF11 | CongestionExperienced, + IfIndex: ifi.Index, + } + cf := ipv6.FlagTrafficClass | ipv6.FlagHopLimit | ipv6.FlagInterface | ipv6.FlagPathMTU + + for i, toggle := range []bool{true, false, true} { + if err := p.SetControlMessage(cf, toggle); err != nil { + t.Fatalf("ipv6.PacketConn.SetControlMessage failed: %v", err) + } + cm.HopLimit = i + 1 + if _, err := p.WriteTo([]byte("HELLO-R-U-THERE"), &cm, dst); err != nil { + t.Fatalf("ipv6.PacketConn.WriteTo failed: %v", err) + } + b := make([]byte, 128) + if _, cm, _, err := p.ReadFrom(b); err != nil { + t.Fatalf("ipv6.PacketConn.ReadFrom failed: %v", err) + } else { + t.Logf("rcvd cmsg: %v", cm) + } + } +} + +func TestPacketConnReadWriteMulticastICMP(t *testing.T) { + switch runtime.GOOS { + case "plan9", "windows": + t.Skipf("not supported on %q", runtime.GOOS) + } + if !supportsIPv6 { + t.Skip("ipv6 is not supported") + } + if os.Getuid() != 0 { + t.Skip("must be root") + } + ifi := loopbackInterface() + if ifi == nil { + t.Skipf("not available on %q", runtime.GOOS) + } + + c, err := net.ListenPacket("ip6:ipv6-icmp", "::") + if err != nil { + t.Fatalf("net.ListenPacket failed: %v", err) + } + defer c.Close() + + dst, err := net.ResolveIPAddr("ip6", "ff02::114") // see RFC 4727 + if err != nil { + t.Fatalf("net.ResolveIPAddr failed: %v", err) + } + + p := ipv6.NewPacketConn(c) + if err := p.JoinGroup(ifi, dst); err != nil { + t.Fatalf("ipv6.PacketConn.JoinGroup on %v failed: %v", ifi, err) + } + if err := p.SetMulticastInterface(ifi); err != nil { + t.Fatalf("ipv6.PacketConn.SetMulticastInterface failed: %v", err) + } + if err := p.SetMulticastLoopback(true); err != nil { + t.Fatalf("ipv6.PacketConn.SetMulticastLoopback failed: %v", err) + } + + cm := ipv6.ControlMessage{ + TrafficClass: DiffServAF11 | CongestionExperienced, + IfIndex: ifi.Index, + } + cf := ipv6.FlagTrafficClass | ipv6.FlagHopLimit | ipv6.FlagInterface | ipv6.FlagPathMTU + + var f ipv6.ICMPFilter + f.SetAll(true) + f.Set(ipv6.ICMPTypeEchoReply, false) + if err := p.SetICMPFilter(&f); err != nil { + t.Fatalf("ipv6.PacketConn.SetICMPFilter failed: %v", err) + } + + for i, toggle := range []bool{true, false, true} { + wb, err := (&icmpMessage{ + Type: ipv6.ICMPTypeEchoRequest, Code: 0, + Body: &icmpEcho{ + ID: os.Getpid() & 0xffff, Seq: i + 1, + Data: []byte("HELLO-R-U-THERE"), + }, + }).Marshal() + if err != nil { + t.Fatalf("icmpMessage.Marshal failed: %v", err) + } + if err := p.SetControlMessage(cf, toggle); err != nil { + t.Fatalf("ipv6.PacketConn.SetControlMessage failed: %v", err) + } + cm.HopLimit = i + 1 + if _, err := p.WriteTo(wb, &cm, dst); err != nil { + t.Fatalf("ipv6.PacketConn.WriteTo failed: %v", err) + } + b := make([]byte, 128) + if n, cm, _, err := p.ReadFrom(b); err != nil { + t.Fatalf("ipv6.PacketConn.ReadFrom failed: %v", err) + } else { + t.Logf("rcvd cmsg: %v", cm) + if m, err := parseICMPMessage(b[:n]); err != nil { + t.Fatalf("parseICMPMessage failed: %v", err) + } else if m.Type != ipv6.ICMPTypeEchoReply || m.Code != 0 { + t.Fatalf("got type=%v, code=%v; expected type=%v, code=%v", m.Type, m.Code, ipv6.ICMPTypeEchoReply, 0) + } + } + } +} diff --git a/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/multicastlistener_test.go b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/multicastlistener_test.go new file mode 100644 index 000000000..836455f4d --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/multicastlistener_test.go @@ -0,0 +1,197 @@ +// 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 ipv6_test + +import ( + "code.google.com/p/go.net/ipv6" + "fmt" + "net" + "os" + "runtime" + "testing" +) + +var udpMultipleGroupListenerTests = []net.Addr{ + &net.UDPAddr{IP: net.ParseIP("ff02::114")}, // see RFC 4727 + &net.UDPAddr{IP: net.ParseIP("ff02::1:114")}, + &net.UDPAddr{IP: net.ParseIP("ff02::2:114")}, +} + +func TestUDPSinglePacketConnWithMultipleGroupListeners(t *testing.T) { + switch runtime.GOOS { + case "plan9", "windows": + t.Skipf("not supported on %q", runtime.GOOS) + } + if !supportsIPv6 { + t.Skip("ipv6 is not supported") + } + + for _, gaddr := range udpMultipleGroupListenerTests { + c, err := net.ListenPacket("udp6", "[::]:0") // wildcard address with non-reusable port + if err != nil { + t.Fatalf("net.ListenPacket failed: %v", err) + } + defer c.Close() + + p := ipv6.NewPacketConn(c) + var mift []*net.Interface + + ift, err := net.Interfaces() + if err != nil { + t.Fatalf("net.Interfaces failed: %v", err) + } + for i, ifi := range ift { + if _, ok := isMulticastAvailable(&ifi); !ok { + continue + } + if err := p.JoinGroup(&ifi, gaddr); err != nil { + t.Fatalf("ipv6.PacketConn.JoinGroup %v on %v failed: %v", gaddr, ifi, err) + } + mift = append(mift, &ift[i]) + } + for _, ifi := range mift { + if err := p.LeaveGroup(ifi, gaddr); err != nil { + t.Fatalf("ipv6.PacketConn.LeaveGroup %v on %v failed: %v", gaddr, ifi, err) + } + } + } +} + +func TestUDPMultipleConnWithMultipleGroupListeners(t *testing.T) { + switch runtime.GOOS { + case "plan9", "windows": + t.Skipf("not supported on %q", runtime.GOOS) + } + if !supportsIPv6 { + t.Skip("ipv6 is not supported") + } + + for _, gaddr := range udpMultipleGroupListenerTests { + c1, err := net.ListenPacket("udp6", "[ff02::]:1024") // wildcard address with reusable port + if err != nil { + t.Fatalf("net.ListenPacket failed: %v", err) + } + defer c1.Close() + + c2, err := net.ListenPacket("udp6", "[ff02::]:1024") // wildcard address with reusable port + if err != nil { + t.Fatalf("net.ListenPacket failed: %v", err) + } + defer c2.Close() + + var ps [2]*ipv6.PacketConn + ps[0] = ipv6.NewPacketConn(c1) + ps[1] = ipv6.NewPacketConn(c2) + var mift []*net.Interface + + ift, err := net.Interfaces() + if err != nil { + t.Fatalf("net.Interfaces failed: %v", err) + } + for i, ifi := range ift { + if _, ok := isMulticastAvailable(&ifi); !ok { + continue + } + for _, p := range ps { + if err := p.JoinGroup(&ifi, gaddr); err != nil { + t.Fatalf("ipv6.PacketConn.JoinGroup %v on %v failed: %v", gaddr, ifi, err) + } + } + mift = append(mift, &ift[i]) + } + for _, ifi := range mift { + for _, p := range ps { + if err := p.LeaveGroup(ifi, gaddr); err != nil { + t.Fatalf("ipv6.PacketConn.LeaveGroup %v on %v failed: %v", gaddr, ifi, err) + } + } + } + } +} + +func TestUDPPerInterfaceSinglePacketConnWithSingleGroupListener(t *testing.T) { + switch runtime.GOOS { + case "plan9", "windows": + t.Skipf("not supported on %q", runtime.GOOS) + } + if !supportsIPv6 { + t.Skip("ipv6 is not supported") + } + + gaddr := &net.IPAddr{IP: net.ParseIP("ff02::114")} // see RFC 4727 + type ml struct { + c *ipv6.PacketConn + ifi *net.Interface + } + var mlt []*ml + + ift, err := net.Interfaces() + if err != nil { + t.Fatalf("net.Interfaces failed: %v", err) + } + for i, ifi := range ift { + ip, ok := isMulticastAvailable(&ifi) + if !ok { + continue + } + c, err := net.ListenPacket("udp6", fmt.Sprintf("[%s%%%s]:1024", ip.String(), ifi.Name)) // unicast address with non-reusable port + if err != nil { + t.Fatalf("net.ListenPacket with %v failed: %v", ip, err) + } + defer c.Close() + p := ipv6.NewPacketConn(c) + if err := p.JoinGroup(&ifi, gaddr); err != nil { + t.Fatalf("ipv6.PacketConn.JoinGroup on %v failed: %v", ifi, err) + } + mlt = append(mlt, &ml{p, &ift[i]}) + } + for _, m := range mlt { + if err := m.c.LeaveGroup(m.ifi, gaddr); err != nil { + t.Fatalf("ipv6.PacketConn.LeaveGroup on %v failed: %v", m.ifi, err) + } + } +} + +func TestIPSinglePacketConnWithSingleGroupListener(t *testing.T) { + switch runtime.GOOS { + case "plan9", "windows": + t.Skipf("not supported on %q", runtime.GOOS) + } + if !supportsIPv6 { + t.Skip("ipv6 is not supported") + } + if os.Getuid() != 0 { + t.Skip("must be root") + } + + c, err := net.ListenPacket("ip6:ipv6-icmp", "::") + if err != nil { + t.Fatalf("net.ListenPacket failed: %v", err) + } + defer c.Close() + + p := ipv6.NewPacketConn(c) + gaddr := &net.IPAddr{IP: net.ParseIP("ff02::114")} // see RFC 4727 + var mift []*net.Interface + + ift, err := net.Interfaces() + if err != nil { + t.Fatalf("net.Interfaces failed: %v", err) + } + for i, ifi := range ift { + if _, ok := isMulticastAvailable(&ifi); !ok { + continue + } + if err := p.JoinGroup(&ifi, gaddr); err != nil { + t.Fatalf("ipv6.PacketConn.JoinGroup on %v failed: %v", ifi, err) + } + mift = append(mift, &ift[i]) + } + for _, ifi := range mift { + if err := p.LeaveGroup(ifi, gaddr); err != nil { + t.Fatalf("ipv6.PacketConn.LeaveGroup on %v failed: %v", ifi, err) + } + } +} diff --git a/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/multicastsockopt_test.go b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/multicastsockopt_test.go new file mode 100644 index 000000000..578c04a02 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/multicastsockopt_test.go @@ -0,0 +1,76 @@ +// 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 ipv6_test + +import ( + "code.google.com/p/go.net/ipv6" + "net" + "os" + "runtime" + "testing" +) + +var packetConnMulticastSocketOptionTests = []struct { + net, proto, addr string + gaddr net.Addr +}{ + {"udp6", "", "[ff02::]:0", &net.UDPAddr{IP: net.ParseIP("ff02::114")}}, // see RFC 4727 + {"ip6", ":ipv6-icmp", "::", &net.IPAddr{IP: net.ParseIP("ff02::114")}}, // see RFC 4727 +} + +func TestPacketConnMulticastSocketOptions(t *testing.T) { + switch runtime.GOOS { + case "plan9", "windows": + t.Skipf("not supported on %q", runtime.GOOS) + } + if !supportsIPv6 { + t.Skip("ipv6 is not supported") + } + ifi := loopbackInterface() + if ifi == nil { + t.Skipf("not available on %q", runtime.GOOS) + } + + for _, tt := range packetConnMulticastSocketOptionTests { + if tt.net == "ip6" && os.Getuid() != 0 { + t.Skip("must be root") + } + c, err := net.ListenPacket(tt.net+tt.proto, tt.addr) + if err != nil { + t.Fatalf("net.ListenPacket failed: %v", err) + } + defer c.Close() + + p := ipv6.NewPacketConn(c) + + hoplim := 255 + if err := p.SetMulticastHopLimit(hoplim); err != nil { + t.Fatalf("ipv6.PacketConn.SetMulticastHopLimit failed: %v", err) + } + if v, err := p.MulticastHopLimit(); err != nil { + t.Fatalf("ipv6.PacketConn.MulticastHopLimit failed: %v", err) + } else if v != hoplim { + t.Fatalf("got unexpected multicast hop limit %v; expected %v", v, hoplim) + } + + for _, toggle := range []bool{true, false} { + if err := p.SetMulticastLoopback(toggle); err != nil { + t.Fatalf("ipv6.PacketConn.SetMulticastLoopback failed: %v", err) + } + if v, err := p.MulticastLoopback(); err != nil { + t.Fatalf("ipv6.PacketConn.MulticastLoopback failed: %v", err) + } else if v != toggle { + t.Fatalf("got unexpected multicast loopback %v; expected %v", v, toggle) + } + } + + if err := p.JoinGroup(ifi, tt.gaddr); err != nil { + t.Fatalf("ipv6.PacketConn.JoinGroup(%v, %v) failed: %v", ifi, tt.gaddr, err) + } + if err := p.LeaveGroup(ifi, tt.gaddr); err != nil { + t.Fatalf("ipv6.PacketConn.LeaveGroup(%v, %v) failed: %v", ifi, tt.gaddr, err) + } + } +} diff --git a/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/payload.go b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/payload.go new file mode 100644 index 000000000..529b20bca --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/payload.go @@ -0,0 +1,15 @@ +// 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 ipv6 + +import "net" + +// A payloadHandler represents the IPv6 datagram payload handler. +type payloadHandler struct { + net.PacketConn + rawOpt +} + +func (c *payloadHandler) ok() bool { return c != nil && c.PacketConn != nil } diff --git a/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/payload_cmsg.go b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/payload_cmsg.go new file mode 100644 index 000000000..658467a6c --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/payload_cmsg.go @@ -0,0 +1,70 @@ +// 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. + +// +build !plan9,!windows + +package ipv6 + +import ( + "net" + "syscall" +) + +// ReadFrom reads a payload of the received IPv6 datagram, from the +// endpoint c, copying the payload into b. It returns the number of +// bytes copied into b, the control message cm and the source address +// src of the received datagram. +func (c *payloadHandler) ReadFrom(b []byte) (n int, cm *ControlMessage, src net.Addr, err error) { + if !c.ok() { + return 0, nil, nil, syscall.EINVAL + } + oob := newControlMessage(&c.rawOpt) + var oobn int + switch c := c.PacketConn.(type) { + case *net.UDPConn: + if n, oobn, _, src, err = c.ReadMsgUDP(b, oob); err != nil { + return 0, nil, nil, err + } + case *net.IPConn: + if n, oobn, _, src, err = c.ReadMsgIP(b, oob); err != nil { + return 0, nil, nil, err + } + default: + return 0, nil, nil, errInvalidConnType + } + if cm, err = parseControlMessage(oob[:oobn]); err != nil { + return 0, nil, nil, err + } + if cm != nil { + cm.Src = netAddrToIP16(src) + } + return +} + +// WriteTo writes a payload of the IPv6 datagram, to the destination +// address dst through the endpoint c, copying the payload from b. It +// returns the number of bytes written. The control message cm allows +// the IPv6 header fields and the datagram path to be specified. The +// cm may be nil if control of the outgoing datagram is not required. +func (c *payloadHandler) WriteTo(b []byte, cm *ControlMessage, dst net.Addr) (n int, err error) { + if !c.ok() { + return 0, syscall.EINVAL + } + oob := marshalControlMessage(cm) + if dst == nil { + return 0, errMissingAddress + } + switch c := c.PacketConn.(type) { + case *net.UDPConn: + n, _, err = c.WriteMsgUDP(b, oob, dst.(*net.UDPAddr)) + case *net.IPConn: + n, _, err = c.WriteMsgIP(b, oob, dst.(*net.IPAddr)) + default: + return 0, errInvalidConnType + } + if err != nil { + return 0, err + } + return +} diff --git a/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/payload_noncmsg.go b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/payload_noncmsg.go new file mode 100644 index 000000000..dd0630a90 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/payload_noncmsg.go @@ -0,0 +1,41 @@ +// 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. + +// +build plan9 windows + +package ipv6 + +import ( + "net" + "syscall" +) + +// ReadFrom reads a payload of the received IPv6 datagram, from the +// endpoint c, copying the payload into b. It returns the number of +// bytes copied into b, the control message cm and the source address +// src of the received datagram. +func (c *payloadHandler) ReadFrom(b []byte) (n int, cm *ControlMessage, src net.Addr, err error) { + if !c.ok() { + return 0, nil, nil, syscall.EINVAL + } + if n, src, err = c.PacketConn.ReadFrom(b); err != nil { + return 0, nil, nil, err + } + return +} + +// WriteTo writes a payload of the IPv6 datagram, to the destination +// address dst through the endpoint c, copying the payload from b. It +// returns the number of bytes written. The control message cm allows +// the IPv6 header fields and the datagram path to be specified. The +// cm may be nil if control of the outgoing datagram is not required. +func (c *payloadHandler) WriteTo(b []byte, cm *ControlMessage, dst net.Addr) (n int, err error) { + if !c.ok() { + return 0, syscall.EINVAL + } + if dst == nil { + return 0, errMissingAddress + } + return c.PacketConn.WriteTo(b, dst) +} diff --git a/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/sockopt_rfc2292_darwin.go b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/sockopt_rfc2292_darwin.go new file mode 100644 index 000000000..f21802c8c --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/sockopt_rfc2292_darwin.go @@ -0,0 +1,66 @@ +// 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 ipv6 + +import ( + "os" + "syscall" +) + +func ipv6ReceiveTrafficClass(fd int) (bool, error) { + return false, errNotSupported +} + +func setIPv6ReceiveTrafficClass(fd int, v bool) error { + return errNotSupported +} + +func ipv6ReceiveHopLimit(fd int) (bool, error) { + v, err := syscall.GetsockoptInt(fd, ianaProtocolIPv6, syscall.IPV6_2292HOPLIMIT) + if err != nil { + return false, os.NewSyscallError("getsockopt", err) + } + return v == 1, nil +} + +func setIPv6ReceiveHopLimit(fd int, v bool) error { + return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIPv6, syscall.IPV6_2292HOPLIMIT, boolint(v))) +} + +func ipv6ReceivePacketInfo(fd int) (bool, error) { + v, err := syscall.GetsockoptInt(fd, ianaProtocolIPv6, syscall.IPV6_2292PKTINFO) + if err != nil { + return false, os.NewSyscallError("getsockopt", err) + } + return v == 1, nil +} + +func setIPv6ReceivePacketInfo(fd int, v bool) error { + return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIPv6, syscall.IPV6_2292PKTINFO, boolint(v))) +} + +func ipv6PathMTU(fd int) (int, error) { + return 0, errNotSupported +} + +func ipv6ReceivePathMTU(fd int) (bool, error) { + return false, errNotSupported +} + +func setIPv6ReceivePathMTU(fd int, v bool) error { + return errNotSupported +} + +func ipv6ICMPFilter(fd int) (*ICMPFilter, error) { + v, err := syscall.GetsockoptICMPv6Filter(fd, ianaProtocolIPv6ICMP, syscall.ICMP6_FILTER) + if err != nil { + return nil, os.NewSyscallError("getsockopt", err) + } + return &ICMPFilter{rawICMPFilter: rawICMPFilter{*v}}, nil +} + +func setIPv6ICMPFilter(fd int, f *ICMPFilter) error { + return os.NewSyscallError("setsockopt", syscall.SetsockoptICMPv6Filter(fd, ianaProtocolIPv6ICMP, syscall.ICMP6_FILTER, &f.rawICMPFilter.ICMPv6Filter)) +} diff --git a/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/sockopt_rfc3493_bsd.go b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/sockopt_rfc3493_bsd.go new file mode 100644 index 000000000..aa5e6e3ab --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/sockopt_rfc3493_bsd.go @@ -0,0 +1,19 @@ +// 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. + +// +build darwin freebsd netbsd openbsd + +package ipv6 + +import ( + "os" + "syscall" +) + +func setIPv6Checksum(fd int, on bool, offset int) error { + if !on { + offset = -1 + } + return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIPv6, syscall.IPV6_CHECKSUM, offset)) +} diff --git a/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/sockopt_rfc3493_linux.go b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/sockopt_rfc3493_linux.go new file mode 100644 index 000000000..b2557e86b --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/sockopt_rfc3493_linux.go @@ -0,0 +1,17 @@ +// 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 ipv6 + +import ( + "os" + "syscall" +) + +func setIPv6Checksum(fd int, on bool, offset int) error { + if !on { + offset = -1 + } + return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolReserved, syscall.IPV6_CHECKSUM, offset)) +} diff --git a/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/sockopt_rfc3493_unix.go b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/sockopt_rfc3493_unix.go new file mode 100644 index 000000000..b055cf043 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/sockopt_rfc3493_unix.go @@ -0,0 +1,114 @@ +// 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. + +// +build darwin freebsd linux netbsd openbsd + +package ipv6 + +import ( + "net" + "os" + "syscall" +) + +func ipv6TrafficClass(fd int) (int, error) { + v, err := syscall.GetsockoptInt(fd, ianaProtocolIPv6, syscall.IPV6_TCLASS) + if err != nil { + return 0, os.NewSyscallError("getsockopt", err) + } + return v, nil +} + +func setIPv6TrafficClass(fd, v int) error { + return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIPv6, syscall.IPV6_TCLASS, v)) +} + +func ipv6HopLimit(fd int) (int, error) { + v, err := syscall.GetsockoptInt(fd, ianaProtocolIPv6, syscall.IPV6_UNICAST_HOPS) + if err != nil { + return 0, os.NewSyscallError("getsockopt", err) + } + return v, nil +} + +func setIPv6HopLimit(fd, v int) error { + return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIPv6, syscall.IPV6_UNICAST_HOPS, v)) +} + +func ipv6Checksum(fd int) (bool, int, error) { + v, err := syscall.GetsockoptInt(fd, ianaProtocolIPv6, syscall.IPV6_CHECKSUM) + if err != nil { + return false, 0, os.NewSyscallError("getsockopt", err) + } + on := true + if v == -1 { + on = false + } + return on, v, nil +} + +func ipv6MulticastHopLimit(fd int) (int, error) { + v, err := syscall.GetsockoptInt(fd, ianaProtocolIPv6, syscall.IPV6_MULTICAST_HOPS) + if err != nil { + return 0, os.NewSyscallError("getsockopt", err) + } + return v, nil +} + +func setIPv6MulticastHopLimit(fd, v int) error { + return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIPv6, syscall.IPV6_MULTICAST_HOPS, v)) +} + +func ipv6MulticastInterface(fd int) (*net.Interface, error) { + v, err := syscall.GetsockoptInt(fd, ianaProtocolIPv6, syscall.IPV6_MULTICAST_IF) + if err != nil { + return nil, os.NewSyscallError("getsockopt", err) + } + if v == 0 { + return nil, nil + } + ifi, err := net.InterfaceByIndex(v) + if err != nil { + return nil, err + } + return ifi, nil +} + +func setIPv6MulticastInterface(fd int, ifi *net.Interface) error { + var v int + if ifi != nil { + v = ifi.Index + } + return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIPv6, syscall.IPV6_MULTICAST_IF, v)) +} + +func ipv6MulticastLoopback(fd int) (bool, error) { + v, err := syscall.GetsockoptInt(fd, ianaProtocolIPv6, syscall.IPV6_MULTICAST_LOOP) + if err != nil { + return false, os.NewSyscallError("getsockopt", err) + } + return v == 1, nil +} + +func setIPv6MulticastLoopback(fd int, v bool) error { + return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIPv6, syscall.IPV6_MULTICAST_LOOP, boolint(v))) +} + +func joinIPv6Group(fd int, ifi *net.Interface, grp net.IP) error { + mreq := syscall.IPv6Mreq{} + copy(mreq.Multiaddr[:], grp) + if ifi != nil { + mreq.Interface = uint32(ifi.Index) + } + return os.NewSyscallError("setsockopt", syscall.SetsockoptIPv6Mreq(fd, ianaProtocolIPv6, syscall.IPV6_JOIN_GROUP, &mreq)) +} + +func leaveIPv6Group(fd int, ifi *net.Interface, grp net.IP) error { + mreq := syscall.IPv6Mreq{} + copy(mreq.Multiaddr[:], grp) + if ifi != nil { + mreq.Interface = uint32(ifi.Index) + } + return os.NewSyscallError("setsockopt", syscall.SetsockoptIPv6Mreq(fd, ianaProtocolIPv6, syscall.IPV6_LEAVE_GROUP, &mreq)) +} diff --git a/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/sockopt_rfc3493_windows.go b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/sockopt_rfc3493_windows.go new file mode 100644 index 000000000..04d4526a1 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/sockopt_rfc3493_windows.go @@ -0,0 +1,116 @@ +// 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 ipv6 + +import ( + "net" + "os" + "syscall" + "unsafe" +) + +func ipv6TrafficClass(fd syscall.Handle) (int, error) { + // TODO(mikio): Implement this + return 0, syscall.EWINDOWS +} + +func setIPv6TrafficClass(fd syscall.Handle, v int) error { + // TODO(mikio): Implement this + return syscall.EWINDOWS +} + +func ipv6HopLimit(fd syscall.Handle) (int, error) { + var v int32 + l := int32(4) + if err := syscall.Getsockopt(fd, ianaProtocolIPv6, syscall.IPV6_UNICAST_HOPS, (*byte)(unsafe.Pointer(&v)), &l); err != nil { + return 0, os.NewSyscallError("getsockopt", err) + } + return int(v), nil +} + +func setIPv6HopLimit(fd syscall.Handle, v int) error { + vv := int32(v) + return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd, ianaProtocolIPv6, syscall.IPV6_UNICAST_HOPS, (*byte)(unsafe.Pointer(&vv)), 4)) +} + +func ipv6Checksum(fd syscall.Handle) (bool, int, error) { + // TODO(mikio): Implement this + return false, 0, syscall.EWINDOWS +} + +func ipv6MulticastHopLimit(fd syscall.Handle) (int, error) { + var v int32 + l := int32(4) + if err := syscall.Getsockopt(fd, ianaProtocolIPv6, syscall.IPV6_MULTICAST_HOPS, (*byte)(unsafe.Pointer(&v)), &l); err != nil { + return 0, os.NewSyscallError("getsockopt", err) + } + return int(v), nil +} + +func setIPv6MulticastHopLimit(fd syscall.Handle, v int) error { + vv := int32(v) + return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd, ianaProtocolIPv6, syscall.IPV6_MULTICAST_HOPS, (*byte)(unsafe.Pointer(&vv)), 4)) +} + +func ipv6MulticastInterface(fd syscall.Handle) (*net.Interface, error) { + var v int32 + l := int32(4) + if err := syscall.Getsockopt(fd, ianaProtocolIPv6, syscall.IPV6_MULTICAST_IF, (*byte)(unsafe.Pointer(&v)), &l); err != nil { + return nil, os.NewSyscallError("getsockopt", err) + } + if v == 0 { + return nil, nil + } + ifi, err := net.InterfaceByIndex(int(v)) + if err != nil { + return nil, err + } + return ifi, nil +} + +func setIPv6MulticastInterface(fd syscall.Handle, ifi *net.Interface) error { + var v int32 + if ifi != nil { + v = int32(ifi.Index) + } + return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd, ianaProtocolIPv6, syscall.IPV6_MULTICAST_IF, (*byte)(unsafe.Pointer(&v)), 4)) +} + +func ipv6MulticastLoopback(fd syscall.Handle) (bool, error) { + var v int32 + l := int32(4) + if err := syscall.Getsockopt(fd, ianaProtocolIPv6, syscall.IPV6_MULTICAST_LOOP, (*byte)(unsafe.Pointer(&v)), &l); err != nil { + return false, os.NewSyscallError("getsockopt", err) + } + return v == 1, nil +} + +func setIPv6MulticastLoopback(fd syscall.Handle, v bool) error { + vv := int32(boolint(v)) + return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd, ianaProtocolIPv6, syscall.IPV6_MULTICAST_LOOP, (*byte)(unsafe.Pointer(&vv)), 4)) +} + +func joinIPv6Group(fd syscall.Handle, ifi *net.Interface, grp net.IP) error { + mreq := syscall.IPv6Mreq{} + copy(mreq.Multiaddr[:], grp) + if ifi != nil { + mreq.Interface = uint32(ifi.Index) + } + return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd, ianaProtocolIPv6, syscall.IPV6_JOIN_GROUP, (*byte)(unsafe.Pointer(&mreq)), int32(unsafe.Sizeof(mreq)))) +} + +func leaveIPv6Group(fd syscall.Handle, ifi *net.Interface, grp net.IP) error { + mreq := syscall.IPv6Mreq{} + copy(mreq.Multiaddr[:], grp) + if ifi != nil { + mreq.Interface = uint32(ifi.Index) + } + return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd, ianaProtocolIPv6, syscall.IPV6_LEAVE_GROUP, (*byte)(unsafe.Pointer(&mreq)), int32(unsafe.Sizeof(mreq)))) +} + +func setIPv6Checksum(fd syscall.Handle, on bool, offset int) error { + // TODO(mikio): Implement this + return syscall.EWINDOWS +} diff --git a/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/sockopt_rfc3542_bsd.go b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/sockopt_rfc3542_bsd.go new file mode 100644 index 000000000..61073b126 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/sockopt_rfc3542_bsd.go @@ -0,0 +1,44 @@ +// 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. + +// +build freebsd netbsd openbsd + +package ipv6 + +import ( + "os" + "syscall" +) + +func ipv6PathMTU(fd int) (int, error) { + v, err := syscall.GetsockoptIPv6MTUInfo(fd, ianaProtocolIPv6, syscall.IPV6_PATHMTU) + if err != nil { + return 0, os.NewSyscallError("getsockopt", err) + } + return int(v.Mtu), nil +} + +func ipv6ReceivePathMTU(fd int) (bool, error) { + v, err := syscall.GetsockoptInt(fd, ianaProtocolIPv6, syscall.IPV6_RECVPATHMTU) + if err != nil { + return false, os.NewSyscallError("getsockopt", err) + } + return v == 1, nil +} + +func setIPv6ReceivePathMTU(fd int, v bool) error { + return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIPv6, syscall.IPV6_RECVPATHMTU, boolint(v))) +} + +func ipv6ICMPFilter(fd int) (*ICMPFilter, error) { + v, err := syscall.GetsockoptICMPv6Filter(fd, ianaProtocolIPv6ICMP, syscall.ICMP6_FILTER) + if err != nil { + return nil, os.NewSyscallError("getsockopt", err) + } + return &ICMPFilter{rawICMPFilter: rawICMPFilter{*v}}, nil +} + +func setIPv6ICMPFilter(fd int, f *ICMPFilter) error { + return os.NewSyscallError("setsockopt", syscall.SetsockoptICMPv6Filter(fd, ianaProtocolIPv6ICMP, syscall.ICMP6_FILTER, &f.rawICMPFilter.ICMPv6Filter)) +} diff --git a/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/sockopt_rfc3542_linux.go b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/sockopt_rfc3542_linux.go new file mode 100644 index 000000000..9cea683f2 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/sockopt_rfc3542_linux.go @@ -0,0 +1,42 @@ +// 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 ipv6 + +import ( + "os" + "syscall" +) + +func ipv6PathMTU(fd int) (int, error) { + v, err := syscall.GetsockoptIPv6MTUInfo(fd, ianaProtocolIPv6, syscall_IPV6_PATHMTU) + if err != nil { + return 0, os.NewSyscallError("getsockopt", err) + } + return int(v.Mtu), nil +} + +func ipv6ReceivePathMTU(fd int) (bool, error) { + v, err := syscall.GetsockoptInt(fd, ianaProtocolIPv6, syscall_IPV6_RECVPATHMTU) + if err != nil { + return false, os.NewSyscallError("getsockopt", err) + } + return v == 1, nil +} + +func setIPv6ReceivePathMTU(fd int, v bool) error { + return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIPv6, syscall_IPV6_RECVPATHMTU, boolint(v))) +} + +func ipv6ICMPFilter(fd int) (*ICMPFilter, error) { + v, err := syscall.GetsockoptICMPv6Filter(fd, ianaProtocolIPv6ICMP, syscall.ICMPV6_FILTER) + if err != nil { + return nil, os.NewSyscallError("getsockopt", err) + } + return &ICMPFilter{rawICMPFilter: rawICMPFilter{*v}}, nil +} + +func setIPv6ICMPFilter(fd int, f *ICMPFilter) error { + return os.NewSyscallError("setsockopt", syscall.SetsockoptICMPv6Filter(fd, ianaProtocolIPv6ICMP, syscall.ICMPV6_FILTER, &f.rawICMPFilter.ICMPv6Filter)) +} diff --git a/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/sockopt_rfc3542_plan9.go b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/sockopt_rfc3542_plan9.go new file mode 100644 index 000000000..53a59f446 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/sockopt_rfc3542_plan9.go @@ -0,0 +1,12 @@ +// 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 ipv6 + +import "syscall" + +func ipv6PathMTU(fd int) (int, error) { + // TODO(mikio): Implement this + return 0, syscall.EPLAN9 +} diff --git a/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/sockopt_rfc3542_unix.go b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/sockopt_rfc3542_unix.go new file mode 100644 index 000000000..463f426b9 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/sockopt_rfc3542_unix.go @@ -0,0 +1,48 @@ +// 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. + +// +build freebsd linux netbsd openbsd + +package ipv6 + +import ( + "os" + "syscall" +) + +func ipv6ReceiveTrafficClass(fd int) (bool, error) { + v, err := syscall.GetsockoptInt(fd, ianaProtocolIPv6, syscall.IPV6_RECVTCLASS) + if err != nil { + return false, os.NewSyscallError("getsockopt", err) + } + return v == 1, nil +} + +func setIPv6ReceiveTrafficClass(fd int, v bool) error { + return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIPv6, syscall.IPV6_RECVTCLASS, boolint(v))) +} + +func ipv6ReceiveHopLimit(fd int) (bool, error) { + v, err := syscall.GetsockoptInt(fd, ianaProtocolIPv6, syscall.IPV6_RECVHOPLIMIT) + if err != nil { + return false, os.NewSyscallError("getsockopt", err) + } + return v == 1, nil +} + +func setIPv6ReceiveHopLimit(fd int, v bool) error { + return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIPv6, syscall.IPV6_RECVHOPLIMIT, boolint(v))) +} + +func ipv6ReceivePacketInfo(fd int) (bool, error) { + v, err := syscall.GetsockoptInt(fd, ianaProtocolIPv6, syscall.IPV6_RECVPKTINFO) + if err != nil { + return false, os.NewSyscallError("getsockopt", err) + } + return v == 1, nil +} + +func setIPv6ReceivePacketInfo(fd int, v bool) error { + return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIPv6, syscall.IPV6_RECVPKTINFO, boolint(v))) +} diff --git a/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/sockopt_rfc3542_windows.go b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/sockopt_rfc3542_windows.go new file mode 100644 index 000000000..2bc22d9a5 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/sockopt_rfc3542_windows.go @@ -0,0 +1,62 @@ +// 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 ipv6 + +import "syscall" + +func ipv6ReceiveTrafficClass(fd syscall.Handle) (bool, error) { + // TODO(mikio): Implement this + return false, syscall.EWINDOWS +} + +func setIPv6ReceiveTrafficClass(fd syscall.Handle, v bool) error { + // TODO(mikio): Implement this + return syscall.EWINDOWS +} + +func ipv6ReceiveHopLimit(fd syscall.Handle) (bool, error) { + // TODO(mikio): Implement this + return false, syscall.EWINDOWS +} + +func setIPv6ReceiveHopLimit(fd syscall.Handle, v bool) error { + // TODO(mikio): Implement this + return syscall.EWINDOWS +} + +func ipv6ReceivePacketInfo(fd syscall.Handle) (bool, error) { + // TODO(mikio): Implement this + return false, syscall.EWINDOWS +} + +func setIPv6ReceivePacketInfo(fd syscall.Handle, v bool) error { + // TODO(mikio): Implement this + return syscall.EWINDOWS +} + +func ipv6PathMTU(fd syscall.Handle) (int, error) { + // TODO(mikio): Implement this + return 0, syscall.EWINDOWS +} + +func ipv6ReceivePathMTU(fd syscall.Handle) (bool, error) { + // TODO(mikio): Implement this + return false, syscall.EWINDOWS +} + +func setIPv6ReceivePathMTU(fd syscall.Handle, v bool) error { + // TODO(mikio): Implement this + return syscall.EWINDOWS +} + +func ipv6ICMPFilter(fd syscall.Handle) (*ICMPFilter, error) { + // TODO(mikio): Implement this + return nil, syscall.EWINDOWS +} + +func setIPv6ICMPFilter(fd syscall.Handle, f *ICMPFilter) error { + // TODO(mikio): Implement this + return syscall.EWINDOWS +} diff --git a/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/sockopt_test.go b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/sockopt_test.go new file mode 100644 index 000000000..e489ca83c --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/sockopt_test.go @@ -0,0 +1,136 @@ +// 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 ipv6_test + +import ( + "code.google.com/p/go.net/ipv6" + "net" + "os" + "runtime" + "testing" +) + +var supportsIPv6 bool + +func init() { + if ln, err := net.Listen("tcp6", "[::1]:0"); err == nil { + ln.Close() + supportsIPv6 = true + } +} + +var condFatalf = func() func(*testing.T, string, ...interface{}) { + // A few APIs are not implemented yet on some platforms. + switch runtime.GOOS { + case "darwin", "plan9", "windows": + return (*testing.T).Logf + } + return (*testing.T).Fatalf +}() + +func TestConnInitiatorPathMTU(t *testing.T) { + switch runtime.GOOS { + case "plan9", "windows": + t.Skipf("not supported on %q", runtime.GOOS) + } + if !supportsIPv6 { + t.Skip("ipv6 is not supported") + } + + ln, err := net.Listen("tcp6", "[::1]:0") + if err != nil { + t.Fatalf("net.Listen failed: %v", err) + } + defer ln.Close() + + done := make(chan bool) + go acceptor(t, ln, done) + + c, err := net.Dial("tcp6", ln.Addr().String()) + if err != nil { + t.Fatalf("net.Dial failed: %v", err) + } + defer c.Close() + + if pmtu, err := ipv6.NewConn(c).PathMTU(); err != nil { + condFatalf(t, "ipv6.Conn.PathMTU failed: %v", err) + } else { + t.Logf("path mtu for %v: %v", c.RemoteAddr(), pmtu) + } + + <-done +} + +func TestConnResponderPathMTU(t *testing.T) { + switch runtime.GOOS { + case "plan9", "windows": + t.Skipf("not supported on %q", runtime.GOOS) + } + if !supportsIPv6 { + t.Skip("ipv6 is not supported") + } + + ln, err := net.Listen("tcp6", "[::1]:0") + if err != nil { + t.Fatalf("net.Listen failed: %v", err) + } + defer ln.Close() + + done := make(chan bool) + go connector(t, "tcp6", ln.Addr().String(), done) + + c, err := ln.Accept() + if err != nil { + t.Fatalf("net.Accept failed: %v", err) + } + defer c.Close() + + if pmtu, err := ipv6.NewConn(c).PathMTU(); err != nil { + condFatalf(t, "ipv6.Conn.PathMTU failed: %v", err) + } else { + t.Logf("path mtu for %v: %v", c.RemoteAddr(), pmtu) + } + + <-done +} + +func TestPacketConnChecksum(t *testing.T) { + switch runtime.GOOS { + case "plan9", "windows": + t.Skipf("not supported on %q", runtime.GOOS) + } + if !supportsIPv6 { + t.Skip("ipv6 is not supported") + } + if os.Getuid() != 0 { + t.Skip("must be root") + } + + c, err := net.ListenPacket("ip6:89", "::") // OSPF for IPv6 + if err != nil { + t.Fatalf("net.ListenPacket failed: %v", err) + } + defer c.Close() + + p := ipv6.NewPacketConn(c) + offset := 12 // see RFC 5340 + + for _, toggle := range []bool{false, true} { + if err := p.SetChecksum(toggle, offset); err != nil { + if toggle { + t.Fatalf("ipv6.PacketConn.SetChecksum(%v, %v) failed: %v", toggle, offset, err) + } else { + // Some platforms never allow to disable the kernel + // checksum processing. + t.Logf("ipv6.PacketConn.SetChecksum(%v, %v) failed: %v", toggle, offset, err) + } + } + if on, offset, err := p.Checksum(); err != nil { + t.Fatalf("ipv6.PacketConn.Checksum failed: %v", err) + } else { + t.Logf("kernel checksum processing enabled=%v, offset=%v", on, offset) + } + } +} diff --git a/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/unicast_test.go b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/unicast_test.go new file mode 100644 index 000000000..c79847dcd --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/unicast_test.go @@ -0,0 +1,203 @@ +// 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 ipv6_test + +import ( + "code.google.com/p/go.net/ipv6" + "net" + "os" + "runtime" + "testing" +) + +func benchmarkUDPListener() (net.PacketConn, net.Addr, error) { + c, err := net.ListenPacket("udp6", "[::1]:0") + if err != nil { + return nil, nil, err + } + dst, err := net.ResolveUDPAddr("udp6", c.LocalAddr().String()) + if err != nil { + c.Close() + return nil, nil, err + } + return c, dst, nil +} + +func BenchmarkReadWriteNetUDP(b *testing.B) { + c, dst, err := benchmarkUDPListener() + if err != nil { + b.Fatalf("benchmarkUDPListener failed: %v", err) + } + defer c.Close() + + wb, rb := []byte("HELLO-R-U-THERE"), make([]byte, 128) + b.ResetTimer() + for i := 0; i < b.N; i++ { + benchmarkReadWriteNetUDP(b, c, wb, rb, dst) + } +} + +func benchmarkReadWriteNetUDP(b *testing.B, c net.PacketConn, wb, rb []byte, dst net.Addr) { + if _, err := c.WriteTo(wb, dst); err != nil { + b.Fatalf("net.PacketConn.WriteTo failed: %v", err) + } + if _, _, err := c.ReadFrom(rb); err != nil { + b.Fatalf("net.PacketConn.ReadFrom failed: %v", err) + } +} + +func BenchmarkReadWriteIPv6UDP(b *testing.B) { + c, dst, err := benchmarkUDPListener() + if err != nil { + b.Fatalf("benchmarkUDPListener failed: %v", err) + } + defer c.Close() + + p := ipv6.NewPacketConn(c) + cf := ipv6.FlagTrafficClass | ipv6.FlagHopLimit | ipv6.FlagInterface | ipv6.FlagPathMTU + if err := p.SetControlMessage(cf, true); err != nil { + b.Fatalf("ipv6.PacketConn.SetControlMessage failed: %v", err) + } + ifi := loopbackInterface() + + wb, rb := []byte("HELLO-R-U-THERE"), make([]byte, 128) + b.ResetTimer() + for i := 0; i < b.N; i++ { + benchmarkReadWriteIPv6UDP(b, p, wb, rb, dst, ifi) + } +} + +func benchmarkReadWriteIPv6UDP(b *testing.B, p *ipv6.PacketConn, wb, rb []byte, dst net.Addr, ifi *net.Interface) { + cm := ipv6.ControlMessage{ + TrafficClass: DiffServAF11 | CongestionExperienced, + HopLimit: 1, + } + if ifi != nil { + cm.IfIndex = ifi.Index + } + if _, err := p.WriteTo(wb, &cm, dst); err != nil { + b.Fatalf("ipv6.PacketConn.WriteTo failed: %v", err) + } + if _, _, _, err := p.ReadFrom(rb); err != nil { + b.Fatalf("ipv6.PacketConn.ReadFrom failed: %v", err) + } +} + +func TestPacketConnReadWriteUnicastUDP(t *testing.T) { + switch runtime.GOOS { + case "plan9", "windows": + t.Skipf("not supported on %q", runtime.GOOS) + } + if !supportsIPv6 { + t.Skip("ipv6 is not supported") + } + + c, err := net.ListenPacket("udp6", "[::1]:0") + if err != nil { + t.Fatalf("net.ListenPacket failed: %v", err) + } + defer c.Close() + + dst, err := net.ResolveUDPAddr("udp6", c.LocalAddr().String()) + if err != nil { + t.Fatalf("net.ResolveUDPAddr failed: %v", err) + } + + p := ipv6.NewPacketConn(c) + cm := ipv6.ControlMessage{ + TrafficClass: DiffServAF11 | CongestionExperienced, + } + cf := ipv6.FlagTrafficClass | ipv6.FlagHopLimit | ipv6.FlagInterface | ipv6.FlagPathMTU + ifi := loopbackInterface() + if ifi != nil { + cm.IfIndex = ifi.Index + } + + for i, toggle := range []bool{true, false, true} { + if err := p.SetControlMessage(cf, toggle); err != nil { + t.Fatalf("ipv6.PacketConn.SetControlMessage failed: %v", err) + } + cm.HopLimit = i + 1 + if _, err := p.WriteTo([]byte("HELLO-R-U-THERE"), &cm, dst); err != nil { + t.Fatalf("ipv6.PacketConn.WriteTo failed: %v", err) + } + b := make([]byte, 128) + if _, cm, _, err := p.ReadFrom(b); err != nil { + t.Fatalf("ipv6.PacketConn.ReadFrom failed: %v", err) + } else { + t.Logf("rcvd cmsg: %v", cm) + } + } +} + +func TestPacketConnReadWriteUnicastICMP(t *testing.T) { + switch runtime.GOOS { + case "plan9", "windows": + t.Skipf("not supported on %q", runtime.GOOS) + } + if !supportsIPv6 { + t.Skip("ipv6 is not supported") + } + if os.Getuid() != 0 { + t.Skip("must be root") + } + + c, err := net.ListenPacket("ip6:ipv6-icmp", "::1") + if err != nil { + t.Fatalf("net.ListenPacket failed: %v", err) + } + defer c.Close() + + dst, err := net.ResolveIPAddr("ip6", "::1") + if err != nil { + t.Fatalf("net.ResolveIPAddr failed: %v", err) + } + + p := ipv6.NewPacketConn(c) + cm := ipv6.ControlMessage{TrafficClass: DiffServAF11 | CongestionExperienced} + cf := ipv6.FlagTrafficClass | ipv6.FlagHopLimit | ipv6.FlagInterface | ipv6.FlagPathMTU + ifi := loopbackInterface() + if ifi != nil { + cm.IfIndex = ifi.Index + } + + var f ipv6.ICMPFilter + f.SetAll(true) + f.Set(ipv6.ICMPTypeEchoReply, false) + if err := p.SetICMPFilter(&f); err != nil { + t.Fatalf("ipv6.PacketConn.SetICMPFilter failed: %v", err) + } + + for i, toggle := range []bool{true, false, true} { + wb, err := (&icmpMessage{ + Type: ipv6.ICMPTypeEchoRequest, Code: 0, + Body: &icmpEcho{ + ID: os.Getpid() & 0xffff, Seq: i + 1, + Data: []byte("HELLO-R-U-THERE"), + }, + }).Marshal() + if err != nil { + t.Fatalf("icmpMessage.Marshal failed: %v", err) + } + if err := p.SetControlMessage(cf, toggle); err != nil { + t.Fatalf("ipv6.PacketConn.SetControlMessage failed: %v", err) + } + cm.HopLimit = i + 1 + if _, err := p.WriteTo(wb, &cm, dst); err != nil { + t.Fatalf("ipv6.PacketConn.WriteTo failed: %v", err) + } + b := make([]byte, 128) + if n, cm, _, err := p.ReadFrom(b); err != nil { + t.Fatalf("ipv6.PacketConn.ReadFrom failed: %v", err) + } else { + t.Logf("rcvd cmsg: %v", cm) + if m, err := parseICMPMessage(b[:n]); err != nil { + t.Fatalf("parseICMPMessage failed: %v", err) + } else if m.Type != ipv6.ICMPTypeEchoReply || m.Code != 0 { + t.Fatalf("got type=%v, code=%v; expected type=%v, code=%v", m.Type, m.Code, ipv6.ICMPTypeEchoReply, 0) + } + } + } +} diff --git a/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/unicastsockopt_test.go b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/unicastsockopt_test.go new file mode 100644 index 000000000..c4a79ea39 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.net/ipv6/unicastsockopt_test.go @@ -0,0 +1,101 @@ +// 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 ipv6_test + +import ( + "code.google.com/p/go.net/ipv6" + "net" + "os" + "runtime" + "testing" +) + +func TestConnUnicastSocketOptions(t *testing.T) { + switch runtime.GOOS { + case "plan9", "windows": + t.Skipf("not supported on %q", runtime.GOOS) + } + if !supportsIPv6 { + t.Skip("ipv6 is not supported") + } + + ln, err := net.Listen("tcp6", "[::1]:0") + if err != nil { + t.Fatalf("net.Listen failed: %v", err) + } + defer ln.Close() + + done := make(chan bool) + go acceptor(t, ln, done) + + c, err := net.Dial("tcp6", ln.Addr().String()) + if err != nil { + t.Fatalf("net.Dial failed: %v", err) + } + defer c.Close() + + testUnicastSocketOptions(t, ipv6.NewConn(c)) + + <-done +} + +var packetConnUnicastSocketOptionTests = []struct { + net, proto, addr string +}{ + {"udp6", "", "[::1]:0"}, + {"ip6", ":ipv6-icmp", "::1"}, +} + +func TestPacketConnUnicastSocketOptions(t *testing.T) { + switch runtime.GOOS { + case "plan9", "windows": + t.Skipf("not supported on %q", runtime.GOOS) + } + if !supportsIPv6 { + t.Skip("ipv6 is not supported") + } + + for _, tt := range packetConnUnicastSocketOptionTests { + if tt.net == "ip6" && os.Getuid() != 0 { + t.Skip("must be root") + } + c, err := net.ListenPacket(tt.net+tt.proto, tt.addr) + if err != nil { + t.Fatalf("net.ListenPacket(%q, %q) failed: %v", tt.net+tt.proto, tt.addr, err) + } + defer c.Close() + + testUnicastSocketOptions(t, ipv6.NewPacketConn(c)) + } +} + +type testIPv6UnicastConn interface { + TrafficClass() (int, error) + SetTrafficClass(int) error + HopLimit() (int, error) + SetHopLimit(int) error +} + +func testUnicastSocketOptions(t *testing.T, c testIPv6UnicastConn) { + tclass := DiffServCS0 | NotECNTransport + if err := c.SetTrafficClass(tclass); err != nil { + t.Fatalf("ipv6.Conn.SetTrafficClass failed: %v", err) + } + if v, err := c.TrafficClass(); err != nil { + t.Fatalf("ipv6.Conn.TrafficClass failed: %v", err) + } else if v != tclass { + t.Fatalf("got unexpected traffic class %v; expected %v", v, tclass) + } + + hoplim := 255 + if err := c.SetHopLimit(hoplim); err != nil { + t.Fatalf("ipv6.Conn.SetHopLimit failed: %v", err) + } + if v, err := c.HopLimit(); err != nil { + t.Fatalf("ipv6.Conn.HopLimit failed: %v", err) + } else if v != hoplim { + t.Fatalf("got unexpected hop limit %v; expected %v", v, hoplim) + } +} diff --git a/Godeps/_workspace/src/code.google.com/p/go.text/transform/examples_test.go b/Godeps/_workspace/src/code.google.com/p/go.text/transform/examples_test.go new file mode 100644 index 000000000..3aff8e141 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.text/transform/examples_test.go @@ -0,0 +1,37 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package transform_test + +import ( + "fmt" + "unicode" + + "code.google.com/p/go.text/transform" + "code.google.com/p/go.text/unicode/norm" +) + +func ExampleRemoveFunc() { + input := []byte(`tschüß; до свидания`) + + b := make([]byte, len(input)) + + t := transform.RemoveFunc(unicode.IsSpace) + n, _, _ := t.Transform(b, input, true) + fmt.Println(string(b[:n])) + + t = transform.RemoveFunc(func(r rune) bool { + return !unicode.Is(unicode.Latin, r) + }) + n, _, _ = t.Transform(b, input, true) + fmt.Println(string(b[:n])) + + n, _, _ = t.Transform(b, norm.NFD.Bytes(input), true) + fmt.Println(string(b[:n])) + + // Output: + // tschüß;досвидания + // tschüß + // tschuß +} diff --git a/Godeps/_workspace/src/code.google.com/p/go.text/transform/transform.go b/Godeps/_workspace/src/code.google.com/p/go.text/transform/transform.go new file mode 100644 index 000000000..b4c79fe73 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.text/transform/transform.go @@ -0,0 +1,496 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package transform provides reader and writer wrappers that transform the +// bytes passing through as well as various transformations. Example +// transformations provided by other packages include normalization and +// conversion between character sets. +package transform + +import ( + "errors" + "io" + "unicode/utf8" +) + +var ( + // ErrShortDst means that the destination buffer was too short to + // receive all of the transformed bytes. + ErrShortDst = errors.New("transform: short destination buffer") + + // ErrShortSrc means that the source buffer has insufficient data to + // complete the transformation. + ErrShortSrc = errors.New("transform: short source buffer") + + // errInconsistentByteCount means that Transform returned success (nil + // error) but also returned nSrc inconsistent with the src argument. + errInconsistentByteCount = errors.New("transform: inconsistent byte count returned") + + // errShortInternal means that an internal buffer is not large enough + // to make progress and the Transform operation must be aborted. + errShortInternal = errors.New("transform: short internal buffer") +) + +// Transformer transforms bytes. +type Transformer interface { + // Transform writes to dst the transformed bytes read from src, and + // returns the number of dst bytes written and src bytes read. The + // atEOF argument tells whether src represents the last bytes of the + // input. + // + // Callers should always process the nDst bytes produced and account + // for the nSrc bytes consumed before considering the error err. + // + // A nil error means that all of the transformed bytes (whether freshly + // transformed from src or left over from previous Transform calls) + // were written to dst. A nil error can be returned regardless of + // whether atEOF is true. If err is nil then nSrc must equal len(src); + // the converse is not necessarily true. + // + // ErrShortDst means that dst was too short to receive all of the + // transformed bytes. ErrShortSrc means that src had insufficient data + // to complete the transformation. If both conditions apply, then + // either error may be returned. Other than the error conditions listed + // here, implementations are free to report other errors that arise. + Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) +} + +// TODO: Do we require that a Transformer be reusable if it returns a nil error +// or do we always require a reset after use? Is Reset mandatory or optional? + +// Reader wraps another io.Reader by transforming the bytes read. +type Reader struct { + r io.Reader + t Transformer + err error + + // dst[dst0:dst1] contains bytes that have been transformed by t but + // not yet copied out via Read. + dst []byte + dst0, dst1 int + + // src[src0:src1] contains bytes that have been read from r but not + // yet transformed through t. + src []byte + src0, src1 int + + // transformComplete is whether the transformation is complete, + // regardless of whether or not it was successful. + transformComplete bool +} + +const defaultBufSize = 4096 + +// NewReader returns a new Reader that wraps r by transforming the bytes read +// via t. +func NewReader(r io.Reader, t Transformer) *Reader { + return &Reader{ + r: r, + t: t, + dst: make([]byte, defaultBufSize), + src: make([]byte, defaultBufSize), + } +} + +// Read implements the io.Reader interface. +func (r *Reader) Read(p []byte) (int, error) { + n, err := 0, error(nil) + for { + // Copy out any transformed bytes and return the final error if we are done. + if r.dst0 != r.dst1 { + n = copy(p, r.dst[r.dst0:r.dst1]) + r.dst0 += n + if r.dst0 == r.dst1 && r.transformComplete { + return n, r.err + } + return n, nil + } else if r.transformComplete { + return 0, r.err + } + + // Try to transform some source bytes, or to flush the transformer if we + // are out of source bytes. We do this even if r.r.Read returned an error. + // As the io.Reader documentation says, "process the n > 0 bytes returned + // before considering the error". + if r.src0 != r.src1 || r.err != nil { + r.dst0 = 0 + r.dst1, n, err = r.t.Transform(r.dst, r.src[r.src0:r.src1], r.err == io.EOF) + r.src0 += n + + switch { + case err == nil: + if r.src0 != r.src1 { + r.err = errInconsistentByteCount + } + // The Transform call was successful; we are complete if we + // cannot read more bytes into src. + r.transformComplete = r.err != nil + continue + case err == ErrShortDst && r.dst1 != 0: + // Make room in dst by copying out, and try again. + continue + case err == ErrShortSrc && r.src1-r.src0 != len(r.src) && r.err == nil: + // Read more bytes into src via the code below, and try again. + default: + r.transformComplete = true + // The reader error (r.err) takes precedence over the + // transformer error (err) unless r.err is nil or io.EOF. + if r.err == nil || r.err == io.EOF { + r.err = err + } + continue + } + } + + // Move any untransformed source bytes to the start of the buffer + // and read more bytes. + if r.src0 != 0 { + r.src0, r.src1 = 0, copy(r.src, r.src[r.src0:r.src1]) + } + n, r.err = r.r.Read(r.src[r.src1:]) + r.src1 += n + } +} + +// TODO: implement ReadByte (and ReadRune??). + +// Writer wraps another io.Writer by transforming the bytes read. +// The user needs to call Close to flush unwritten bytes that may +// be buffered. +type Writer struct { + w io.Writer + t Transformer + dst []byte + + // src[:n] contains bytes that have not yet passed through t. + src []byte + n int +} + +// NewWriter returns a new Writer that wraps w by transforming the bytes written +// via t. +func NewWriter(w io.Writer, t Transformer) *Writer { + return &Writer{ + w: w, + t: t, + dst: make([]byte, defaultBufSize), + src: make([]byte, defaultBufSize), + } +} + +// Write implements the io.Writer interface. If there are not enough +// bytes available to complete a Transform, the bytes will be buffered +// for the next write. Call Close to convert the remaining bytes. +func (w *Writer) Write(data []byte) (n int, err error) { + src := data + if w.n > 0 { + // Append bytes from data to the last remainder. + // TODO: limit the amount copied on first try. + n = copy(w.src[w.n:], data) + w.n += n + src = w.src[:w.n] + } + for { + nDst, nSrc, err := w.t.Transform(w.dst, src, false) + if _, werr := w.w.Write(w.dst[:nDst]); werr != nil { + return n, werr + } + src = src[nSrc:] + if w.n > 0 && len(src) <= n { + // Enough bytes from w.src have been consumed. We make src point + // to data instead to reduce the copying. + w.n = 0 + n -= len(src) + src = data[n:] + if n < len(data) && (err == nil || err == ErrShortSrc) { + continue + } + } else { + n += nSrc + } + switch { + case err == ErrShortDst && nDst > 0: + case err == ErrShortSrc && len(src) < len(w.src): + m := copy(w.src, src) + // If w.n > 0, bytes from data were already copied to w.src and n + // was already set to the number of bytes consumed. + if w.n == 0 { + n += m + } + w.n = m + return n, nil + case err == nil && w.n > 0: + return n, errInconsistentByteCount + default: + return n, err + } + } +} + +// Close implements the io.Closer interface. +func (w *Writer) Close() error { + for src := w.src[:w.n]; len(src) > 0; { + nDst, nSrc, err := w.t.Transform(w.dst, src, true) + if nDst == 0 { + return err + } + if _, werr := w.w.Write(w.dst[:nDst]); werr != nil { + return werr + } + if err != ErrShortDst { + return err + } + src = src[nSrc:] + } + return nil +} + +type nop struct{} + +func (nop) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) { + n := copy(dst, src) + if n < len(src) { + err = ErrShortDst + } + return n, n, err +} + +type discard struct{} + +func (discard) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) { + return 0, len(src), nil +} + +var ( + // Discard is a Transformer for which all Transform calls succeed + // by consuming all bytes and writing nothing. + Discard Transformer = discard{} + + // Nop is a Transformer that copies src to dst. + Nop Transformer = nop{} +) + +// chain is a sequence of links. A chain with N Transformers has N+1 links and +// N+1 buffers. Of those N+1 buffers, the first and last are the src and dst +// buffers given to chain.Transform and the middle N-1 buffers are intermediate +// buffers owned by the chain. The i'th link transforms bytes from the i'th +// buffer chain.link[i].b at read offset chain.link[i].p to the i+1'th buffer +// chain.link[i+1].b at write offset chain.link[i+1].n, for i in [0, N). +type chain struct { + link []link + err error + // errStart is the index at which the error occurred plus 1. Processing + // errStart at this level at the next call to Transform. As long as + // errStart > 0, chain will not consume any more source bytes. + errStart int +} + +func (c *chain) fatalError(errIndex int, err error) { + if i := errIndex + 1; i > c.errStart { + c.errStart = i + c.err = err + } +} + +type link struct { + t Transformer + // b[p:n] holds the bytes to be transformed by t. + b []byte + p int + n int +} + +func (l *link) src() []byte { + return l.b[l.p:l.n] +} + +func (l *link) dst() []byte { + return l.b[l.n:] +} + +// Chain returns a Transformer that applies t in sequence. +func Chain(t ...Transformer) Transformer { + if len(t) == 0 { + return nop{} + } + c := &chain{link: make([]link, len(t)+1)} + for i, tt := range t { + c.link[i].t = tt + } + // Allocate intermediate buffers. + b := make([][defaultBufSize]byte, len(t)-1) + for i := range b { + c.link[i+1].b = b[i][:] + } + return c +} + +// Transform applies the transformers of c in sequence. +func (c *chain) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) { + // Set up src and dst in the chain. + srcL := &c.link[0] + dstL := &c.link[len(c.link)-1] + srcL.b, srcL.p, srcL.n = src, 0, len(src) + dstL.b, dstL.n = dst, 0 + var lastFull, needProgress bool // for detecting progress + + // i is the index of the next Transformer to apply, for i in [low, high]. + // low is the lowest index for which c.link[low] may still produce bytes. + // high is the highest index for which c.link[high] has a Transformer. + // The error returned by Transform determines whether to increase or + // decrease i. We try to completely fill a buffer before converting it. + for low, i, high := c.errStart, c.errStart, len(c.link)-2; low <= i && i <= high; { + in, out := &c.link[i], &c.link[i+1] + nDst, nSrc, err0 := in.t.Transform(out.dst(), in.src(), atEOF && low == i) + out.n += nDst + in.p += nSrc + if i > 0 && in.p == in.n { + in.p, in.n = 0, 0 + } + needProgress, lastFull = lastFull, false + switch err0 { + case ErrShortDst: + // Process the destination buffer next. Return if we are already + // at the high index. + if i == high { + return dstL.n, srcL.p, ErrShortDst + } + if out.n != 0 { + i++ + // If the Transformer at the next index is not able to process any + // source bytes there is nothing that can be done to make progress + // and the bytes will remain unprocessed. lastFull is used to + // detect this and break out of the loop with a fatal error. + lastFull = true + continue + } + // The destination buffer was too small, but is completely empty. + // Return a fatal error as this transformation can never complete. + c.fatalError(i, errShortInternal) + case ErrShortSrc: + if i == 0 { + // Save ErrShortSrc in err. All other errors take precedence. + err = ErrShortSrc + break + } + // Source bytes were depleted before filling up the destination buffer. + // Verify we made some progress, move the remaining bytes to the errStart + // and try to get more source bytes. + if needProgress && nSrc == 0 || in.n-in.p == len(in.b) { + // There were not enough source bytes to proceed while the source + // buffer cannot hold any more bytes. Return a fatal error as this + // transformation can never complete. + c.fatalError(i, errShortInternal) + break + } + // in.b is an internal buffer and we can make progress. + in.p, in.n = 0, copy(in.b, in.src()) + fallthrough + case nil: + // if i == low, we have depleted the bytes at index i or any lower levels. + // In that case we increase low and i. In all other cases we decrease i to + // fetch more bytes before proceeding to the next index. + if i > low { + i-- + continue + } + default: + c.fatalError(i, err0) + } + // Exhausted level low or fatal error: increase low and continue + // to process the bytes accepted so far. + i++ + low = i + } + + // If c.errStart > 0, this means we found a fatal error. We will clear + // all upstream buffers. At this point, no more progress can be made + // downstream, as Transform would have bailed while handling ErrShortDst. + if c.errStart > 0 { + for i := 1; i < c.errStart; i++ { + c.link[i].p, c.link[i].n = 0, 0 + } + err, c.errStart, c.err = c.err, 0, nil + } + return dstL.n, srcL.p, err +} + +// RemoveFunc returns a Transformer that removes from the input all runes r for +// which f(r) is true. Illegal bytes in the input are replaced by RuneError. +func RemoveFunc(f func(r rune) bool) Transformer { + return removeF(f) +} + +type removeF func(r rune) bool + +// Transform implements the Transformer interface. +func (t removeF) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) { + for r, sz := rune(0), 0; len(src) > 0; src = src[sz:] { + + if r = rune(src[0]); r < utf8.RuneSelf { + sz = 1 + } else { + r, sz = utf8.DecodeRune(src) + + if sz == 1 { + // Invalid rune. + if !atEOF && !utf8.FullRune(src[nSrc:]) { + err = ErrShortSrc + break + } + // We replace illegal bytes with RuneError. Not doing so might + // otherwise turn a sequence of invalid UTF-8 into valid UTF-8. + // The resulting byte sequence may subsequently contain runes + // for which t(r) is true that were passed unnoticed. + if !t(r) { + if nDst+3 > len(dst) { + err = ErrShortDst + break + } + nDst += copy(dst[nDst:], "\uFFFD") + } + nSrc++ + continue + } + } + + if !t(r) { + if nDst+sz > len(dst) { + err = ErrShortDst + break + } + nDst += copy(dst[nDst:], src[:sz]) + } + nSrc += sz + } + return +} + +// Bytes returns a new byte slice with the result of converting b using t. +// If any unrecoverable error occurs it returns nil. +func Bytes(t Transformer, b []byte) []byte { + out := make([]byte, len(b)) + n := 0 + for { + nDst, nSrc, err := t.Transform(out[n:], b, true) + n += nDst + if err == nil { + return out[:n] + } else if err != ErrShortDst { + return nil + } + b = b[nSrc:] + + // Grow the destination buffer. + sz := len(out) + if sz <= 256 { + sz *= 2 + } else { + sz += sz >> 1 + } + out2 := make([]byte, sz) + copy(out2, out[:n]) + out = out2 + } +} diff --git a/Godeps/_workspace/src/code.google.com/p/go.text/transform/transform_test.go b/Godeps/_workspace/src/code.google.com/p/go.text/transform/transform_test.go new file mode 100644 index 000000000..7444a18dd --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.text/transform/transform_test.go @@ -0,0 +1,901 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package transform + +import ( + "bytes" + "errors" + "fmt" + "io/ioutil" + "strconv" + "strings" + "testing" + "unicode/utf8" +) + +type lowerCaseASCII struct{} + +func (lowerCaseASCII) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) { + n := len(src) + if n > len(dst) { + n, err = len(dst), ErrShortDst + } + for i, c := range src[:n] { + if 'A' <= c && c <= 'Z' { + c += 'a' - 'A' + } + dst[i] = c + } + return n, n, err +} + +var errYouMentionedX = errors.New("you mentioned X") + +type dontMentionX struct{} + +func (dontMentionX) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) { + n := len(src) + if n > len(dst) { + n, err = len(dst), ErrShortDst + } + for i, c := range src[:n] { + if c == 'X' { + return i, i, errYouMentionedX + } + dst[i] = c + } + return n, n, err +} + +// doublerAtEOF is a strange Transformer that transforms "this" to "tthhiiss", +// but only if atEOF is true. +type doublerAtEOF struct{} + +func (doublerAtEOF) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) { + if !atEOF { + return 0, 0, ErrShortSrc + } + for i, c := range src { + if 2*i+2 >= len(dst) { + return 2 * i, i, ErrShortDst + } + dst[2*i+0] = c + dst[2*i+1] = c + } + return 2 * len(src), len(src), nil +} + +// rleDecode and rleEncode implement a toy run-length encoding: "aabbbbbbbbbb" +// is encoded as "2a10b". The decoding is assumed to not contain any numbers. + +type rleDecode struct{} + +func (rleDecode) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) { +loop: + for len(src) > 0 { + n := 0 + for i, c := range src { + if '0' <= c && c <= '9' { + n = 10*n + int(c-'0') + continue + } + if i == 0 { + return nDst, nSrc, errors.New("rleDecode: bad input") + } + if n > len(dst) { + return nDst, nSrc, ErrShortDst + } + for j := 0; j < n; j++ { + dst[j] = c + } + dst, src = dst[n:], src[i+1:] + nDst, nSrc = nDst+n, nSrc+i+1 + continue loop + } + if atEOF { + return nDst, nSrc, errors.New("rleDecode: bad input") + } + return nDst, nSrc, ErrShortSrc + } + return nDst, nSrc, nil +} + +type rleEncode struct { + // allowStutter means that "xxxxxxxx" can be encoded as "5x3x" + // instead of always as "8x". + allowStutter bool +} + +func (e rleEncode) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) { + for len(src) > 0 { + n, c0 := len(src), src[0] + for i, c := range src[1:] { + if c != c0 { + n = i + 1 + break + } + } + if n == len(src) && !atEOF && !e.allowStutter { + return nDst, nSrc, ErrShortSrc + } + s := strconv.Itoa(n) + if len(s) >= len(dst) { + return nDst, nSrc, ErrShortDst + } + copy(dst, s) + dst[len(s)] = c0 + dst, src = dst[len(s)+1:], src[n:] + nDst, nSrc = nDst+len(s)+1, nSrc+n + } + return nDst, nSrc, nil +} + +type testCase struct { + desc string + t Transformer + src string + dstSize int + srcSize int + ioSize int + wantStr string + wantErr error + wantIter int // number of iterations taken; 0 means we don't care. +} + +func (t testCase) String() string { + return tstr(t.t) + "; " + t.desc +} + +func tstr(t Transformer) string { + if stringer, ok := t.(fmt.Stringer); ok { + return stringer.String() + } + s := fmt.Sprintf("%T", t) + return s[1+strings.Index(s, "."):] +} + +func (c chain) String() string { + buf := &bytes.Buffer{} + buf.WriteString("Chain(") + for i, l := range c.link[:len(c.link)-1] { + if i != 0 { + fmt.Fprint(buf, ", ") + } + buf.WriteString(tstr(l.t)) + } + buf.WriteString(")") + return buf.String() +} + +var testCases = []testCase{ + { + desc: "basic", + t: lowerCaseASCII{}, + src: "Hello WORLD.", + dstSize: 100, + srcSize: 100, + wantStr: "hello world.", + }, + + { + desc: "small dst", + t: lowerCaseASCII{}, + src: "Hello WORLD.", + dstSize: 3, + srcSize: 100, + wantStr: "hello world.", + }, + + { + desc: "small src", + t: lowerCaseASCII{}, + src: "Hello WORLD.", + dstSize: 100, + srcSize: 4, + wantStr: "hello world.", + }, + + { + desc: "small buffers", + t: lowerCaseASCII{}, + src: "Hello WORLD.", + dstSize: 3, + srcSize: 4, + wantStr: "hello world.", + }, + + { + desc: "very small buffers", + t: lowerCaseASCII{}, + src: "Hello WORLD.", + dstSize: 1, + srcSize: 1, + wantStr: "hello world.", + }, + + { + desc: "basic", + t: dontMentionX{}, + src: "The First Rule of Transform Club: don't mention Mister X, ever.", + dstSize: 100, + srcSize: 100, + wantStr: "The First Rule of Transform Club: don't mention Mister ", + wantErr: errYouMentionedX, + }, + + { + desc: "small buffers", + t: dontMentionX{}, + src: "The First Rule of Transform Club: don't mention Mister X, ever.", + dstSize: 10, + srcSize: 10, + wantStr: "The First Rule of Transform Club: don't mention Mister ", + wantErr: errYouMentionedX, + }, + + { + desc: "very small buffers", + t: dontMentionX{}, + src: "The First Rule of Transform Club: don't mention Mister X, ever.", + dstSize: 1, + srcSize: 1, + wantStr: "The First Rule of Transform Club: don't mention Mister ", + wantErr: errYouMentionedX, + }, + + { + desc: "only transform at EOF", + t: doublerAtEOF{}, + src: "this", + dstSize: 100, + srcSize: 100, + wantStr: "tthhiiss", + }, + + { + desc: "basic", + t: rleDecode{}, + src: "1a2b3c10d11e0f1g", + dstSize: 100, + srcSize: 100, + wantStr: "abbcccddddddddddeeeeeeeeeeeg", + }, + + { + desc: "long", + t: rleDecode{}, + src: "12a23b34c45d56e99z", + dstSize: 100, + srcSize: 100, + wantStr: strings.Repeat("a", 12) + + strings.Repeat("b", 23) + + strings.Repeat("c", 34) + + strings.Repeat("d", 45) + + strings.Repeat("e", 56) + + strings.Repeat("z", 99), + }, + + { + desc: "tight buffers", + t: rleDecode{}, + src: "1a2b3c10d11e0f1g", + dstSize: 11, + srcSize: 3, + wantStr: "abbcccddddddddddeeeeeeeeeeeg", + }, + + { + desc: "short dst", + t: rleDecode{}, + src: "1a2b3c10d11e0f1g", + dstSize: 10, + srcSize: 3, + wantStr: "abbcccdddddddddd", + wantErr: ErrShortDst, + }, + + { + desc: "short src", + t: rleDecode{}, + src: "1a2b3c10d11e0f1g", + dstSize: 11, + srcSize: 2, + ioSize: 2, + wantStr: "abbccc", + wantErr: ErrShortSrc, + }, + + { + desc: "basic", + t: rleEncode{}, + src: "abbcccddddddddddeeeeeeeeeeeg", + dstSize: 100, + srcSize: 100, + wantStr: "1a2b3c10d11e1g", + }, + + { + desc: "long", + t: rleEncode{}, + src: strings.Repeat("a", 12) + + strings.Repeat("b", 23) + + strings.Repeat("c", 34) + + strings.Repeat("d", 45) + + strings.Repeat("e", 56) + + strings.Repeat("z", 99), + dstSize: 100, + srcSize: 100, + wantStr: "12a23b34c45d56e99z", + }, + + { + desc: "tight buffers", + t: rleEncode{}, + src: "abbcccddddddddddeeeeeeeeeeeg", + dstSize: 3, + srcSize: 12, + wantStr: "1a2b3c10d11e1g", + }, + + { + desc: "short dst", + t: rleEncode{}, + src: "abbcccddddddddddeeeeeeeeeeeg", + dstSize: 2, + srcSize: 12, + wantStr: "1a2b3c", + wantErr: ErrShortDst, + }, + + { + desc: "short src", + t: rleEncode{}, + src: "abbcccddddddddddeeeeeeeeeeeg", + dstSize: 3, + srcSize: 11, + ioSize: 11, + wantStr: "1a2b3c10d", + wantErr: ErrShortSrc, + }, + + { + desc: "allowStutter = false", + t: rleEncode{allowStutter: false}, + src: "aaaabbbbbbbbccccddddd", + dstSize: 10, + srcSize: 10, + wantStr: "4a8b4c5d", + }, + + { + desc: "allowStutter = true", + t: rleEncode{allowStutter: true}, + src: "aaaabbbbbbbbccccddddd", + dstSize: 10, + srcSize: 10, + ioSize: 10, + wantStr: "4a6b2b4c4d1d", + }, +} + +func TestReader(t *testing.T) { + for _, tc := range testCases { + reset(tc.t) + r := NewReader(strings.NewReader(tc.src), tc.t) + // Differently sized dst and src buffers are not part of the + // exported API. We override them manually. + r.dst = make([]byte, tc.dstSize) + r.src = make([]byte, tc.srcSize) + got, err := ioutil.ReadAll(r) + str := string(got) + if str != tc.wantStr || err != tc.wantErr { + t.Errorf("%s:\ngot %q, %v\nwant %q, %v", tc, str, err, tc.wantStr, tc.wantErr) + } + } +} + +func reset(t Transformer) { + var dst [128]byte + for err := ErrShortDst; err != nil; { + _, _, err = t.Transform(dst[:], nil, true) + } +} + +func TestWriter(t *testing.T) { + tests := append(testCases, chainTests()...) + for _, tc := range tests { + sizes := []int{1, 2, 3, 4, 5, 10, 100, 1000} + if tc.ioSize > 0 { + sizes = []int{tc.ioSize} + } + for _, sz := range sizes { + bb := &bytes.Buffer{} + reset(tc.t) + w := NewWriter(bb, tc.t) + // Differently sized dst and src buffers are not part of the + // exported API. We override them manually. + w.dst = make([]byte, tc.dstSize) + w.src = make([]byte, tc.srcSize) + src := make([]byte, sz) + var err error + for b := tc.src; len(b) > 0 && err == nil; { + n := copy(src, b) + b = b[n:] + m := 0 + m, err = w.Write(src[:n]) + if m != n && err == nil { + t.Errorf("%s:%d: did not consume all bytes %d < %d", tc, sz, m, n) + } + } + if err == nil { + err = w.Close() + } + str := bb.String() + if str != tc.wantStr || err != tc.wantErr { + t.Errorf("%s:%d:\ngot %q, %v\nwant %q, %v", tc, sz, str, err, tc.wantStr, tc.wantErr) + } + } + } +} + +func TestNop(t *testing.T) { + testCases := []struct { + str string + dstSize int + err error + }{ + {"", 0, nil}, + {"", 10, nil}, + {"a", 0, ErrShortDst}, + {"a", 1, nil}, + {"a", 10, nil}, + } + for i, tc := range testCases { + dst := make([]byte, tc.dstSize) + nDst, nSrc, err := Nop.Transform(dst, []byte(tc.str), true) + want := tc.str + if tc.dstSize < len(want) { + want = want[:tc.dstSize] + } + if got := string(dst[:nDst]); got != want || err != tc.err || nSrc != nDst { + t.Errorf("%d:\ngot %q, %d, %v\nwant %q, %d, %v", i, got, nSrc, err, want, nDst, tc.err) + } + } +} + +func TestDiscard(t *testing.T) { + testCases := []struct { + str string + dstSize int + }{ + {"", 0}, + {"", 10}, + {"a", 0}, + {"ab", 10}, + } + for i, tc := range testCases { + nDst, nSrc, err := Discard.Transform(make([]byte, tc.dstSize), []byte(tc.str), true) + if nDst != 0 || nSrc != len(tc.str) || err != nil { + t.Errorf("%d:\ngot %q, %d, %v\nwant 0, %d, nil", i, nDst, nSrc, err, len(tc.str)) + } + } +} + +// mkChain creates a Chain transformer. x must be alternating between transformer +// and bufSize, like T, (sz, T)* +func mkChain(x ...interface{}) *chain { + t := []Transformer{} + for i := 0; i < len(x); i += 2 { + t = append(t, x[i].(Transformer)) + } + c := Chain(t...).(*chain) + for i, j := 1, 1; i < len(x); i, j = i+2, j+1 { + c.link[j].b = make([]byte, x[i].(int)) + } + return c +} + +func chainTests() []testCase { + return []testCase{ + { + desc: "nil error", + t: mkChain(rleEncode{}, 100, lowerCaseASCII{}), + src: "ABB", + dstSize: 100, + srcSize: 100, + wantStr: "1a2b", + wantErr: nil, + wantIter: 1, + }, + + { + desc: "short dst buffer", + t: mkChain(lowerCaseASCII{}, 3, rleDecode{}), + src: "1a2b3c10d11e0f1g", + dstSize: 10, + srcSize: 3, + wantStr: "abbcccdddddddddd", + wantErr: ErrShortDst, + }, + + { + desc: "short internal dst buffer", + t: mkChain(lowerCaseASCII{}, 3, rleDecode{}, 10, Nop), + src: "1a2b3c10d11e0f1g", + dstSize: 100, + srcSize: 3, + wantStr: "abbcccdddddddddd", + wantErr: errShortInternal, + }, + + { + desc: "short internal dst buffer from input", + t: mkChain(rleDecode{}, 10, Nop), + src: "1a2b3c10d11e0f1g", + dstSize: 100, + srcSize: 3, + wantStr: "abbcccdddddddddd", + wantErr: errShortInternal, + }, + + { + desc: "empty short internal dst buffer", + t: mkChain(lowerCaseASCII{}, 3, rleDecode{}, 10, Nop), + src: "4a7b11e0f1g", + dstSize: 100, + srcSize: 3, + wantStr: "aaaabbbbbbb", + wantErr: errShortInternal, + }, + + { + desc: "empty short internal dst buffer from input", + t: mkChain(rleDecode{}, 10, Nop), + src: "4a7b11e0f1g", + dstSize: 100, + srcSize: 3, + wantStr: "aaaabbbbbbb", + wantErr: errShortInternal, + }, + + { + desc: "short internal src buffer after full dst buffer", + t: mkChain(Nop, 5, rleEncode{}, 10, Nop), + src: "cccccddddd", + dstSize: 100, + srcSize: 100, + wantStr: "", + wantErr: errShortInternal, + wantIter: 1, + }, + + { + desc: "short internal src buffer after short dst buffer; test lastFull", + t: mkChain(rleDecode{}, 5, rleEncode{}, 4, Nop), + src: "2a1b4c6d", + dstSize: 100, + srcSize: 100, + wantStr: "2a1b", + wantErr: errShortInternal, + }, + + { + desc: "short internal src buffer after successful complete fill", + t: mkChain(Nop, 3, rleDecode{}), + src: "123a4b", + dstSize: 4, + srcSize: 3, + wantStr: "", + wantErr: errShortInternal, + wantIter: 1, + }, + + { + desc: "short internal src buffer after short dst buffer; test lastFull", + t: mkChain(rleDecode{}, 5, rleEncode{}), + src: "2a1b4c6d", + dstSize: 4, + srcSize: 100, + wantStr: "2a1b", + wantErr: errShortInternal, + }, + + { + desc: "short src buffer", + t: mkChain(rleEncode{}, 5, Nop), + src: "abbcccddddeeeee", + dstSize: 4, + srcSize: 4, + ioSize: 4, + wantStr: "1a2b3c", + wantErr: ErrShortSrc, + }, + + { + desc: "process all in one go", + t: mkChain(rleEncode{}, 5, Nop), + src: "abbcccddddeeeeeffffff", + dstSize: 100, + srcSize: 100, + wantStr: "1a2b3c4d5e6f", + wantErr: nil, + wantIter: 1, + }, + + { + desc: "complete processing downstream after error", + t: mkChain(dontMentionX{}, 2, rleDecode{}, 5, Nop), + src: "3a4b5eX", + dstSize: 100, + srcSize: 100, + ioSize: 100, + wantStr: "aaabbbbeeeee", + wantErr: errYouMentionedX, + }, + + { + desc: "return downstream fatal errors first (followed by short dst)", + t: mkChain(dontMentionX{}, 8, rleDecode{}, 4, Nop), + src: "3a4b5eX", + dstSize: 100, + srcSize: 100, + ioSize: 100, + wantStr: "aaabbbb", + wantErr: errShortInternal, + }, + + { + desc: "return downstream fatal errors first (followed by short src)", + t: mkChain(dontMentionX{}, 5, Nop, 1, rleDecode{}), + src: "1a5bX", + dstSize: 100, + srcSize: 100, + ioSize: 100, + wantStr: "", + wantErr: errShortInternal, + }, + + { + desc: "short internal", + t: mkChain(Nop, 11, rleEncode{}, 3, Nop), + src: "abbcccddddddddddeeeeeeeeeeeg", + dstSize: 3, + srcSize: 100, + wantStr: "1a2b3c10d", + wantErr: errShortInternal, + }, + } +} + +func doTransform(tc testCase) (res string, iter int, err error) { + reset(tc.t) + dst := make([]byte, tc.dstSize) + out, in := make([]byte, 0, 2*len(tc.src)), []byte(tc.src) + for { + iter++ + src, atEOF := in, true + if len(src) > tc.srcSize { + src, atEOF = src[:tc.srcSize], false + } + nDst, nSrc, err := tc.t.Transform(dst, src, atEOF) + out = append(out, dst[:nDst]...) + in = in[nSrc:] + switch { + case err == nil && len(in) != 0: + case err == ErrShortSrc && nSrc > 0: + case err == ErrShortDst && nDst > 0: + default: + return string(out), iter, err + } + } +} + +func TestChain(t *testing.T) { + if c, ok := Chain().(nop); !ok { + t.Errorf("empty chain: %v; want Nop", c) + } + + // Test Chain for a single Transformer. + for _, tc := range testCases { + tc.t = Chain(tc.t) + str, _, err := doTransform(tc) + if str != tc.wantStr || err != tc.wantErr { + t.Errorf("%s:\ngot %q, %v\nwant %q, %v", tc, str, err, tc.wantStr, tc.wantErr) + } + } + + tests := chainTests() + sizes := []int{1, 2, 3, 4, 5, 7, 10, 100, 1000} + addTest := func(tc testCase, t *chain) { + if t.link[0].t != tc.t && tc.wantErr == ErrShortSrc { + tc.wantErr = errShortInternal + } + if t.link[len(t.link)-2].t != tc.t && tc.wantErr == ErrShortDst { + tc.wantErr = errShortInternal + } + tc.t = t + tests = append(tests, tc) + } + for _, tc := range testCases { + for _, sz := range sizes { + tt := tc + tt.dstSize = sz + addTest(tt, mkChain(tc.t, tc.dstSize, Nop)) + addTest(tt, mkChain(tc.t, tc.dstSize, Nop, 2, Nop)) + addTest(tt, mkChain(Nop, tc.srcSize, tc.t, tc.dstSize, Nop)) + if sz >= tc.dstSize && (tc.wantErr != ErrShortDst || sz == tc.dstSize) { + addTest(tt, mkChain(Nop, tc.srcSize, tc.t)) + addTest(tt, mkChain(Nop, 100, Nop, tc.srcSize, tc.t)) + } + } + } + for _, tc := range testCases { + tt := tc + tt.dstSize = 1 + tt.wantStr = "" + addTest(tt, mkChain(tc.t, tc.dstSize, Discard)) + addTest(tt, mkChain(Nop, tc.srcSize, tc.t, tc.dstSize, Discard)) + addTest(tt, mkChain(Nop, tc.srcSize, tc.t, tc.dstSize, Nop, tc.dstSize, Discard)) + } + for _, tc := range testCases { + tt := tc + tt.dstSize = 100 + tt.wantStr = strings.Replace(tc.src, "0f", "", -1) + // Chain encoders and decoders. + if _, ok := tc.t.(rleEncode); ok && tc.wantErr == nil { + addTest(tt, mkChain(tc.t, tc.dstSize, Nop, 1000, rleDecode{})) + addTest(tt, mkChain(tc.t, tc.dstSize, Nop, tc.dstSize, rleDecode{})) + addTest(tt, mkChain(Nop, tc.srcSize, tc.t, tc.dstSize, Nop, 100, rleDecode{})) + // decoding needs larger destinations + addTest(tt, mkChain(Nop, tc.srcSize, tc.t, tc.dstSize, rleDecode{}, 100, Nop)) + addTest(tt, mkChain(Nop, tc.srcSize, tc.t, tc.dstSize, Nop, 100, rleDecode{}, 100, Nop)) + } else if _, ok := tc.t.(rleDecode); ok && tc.wantErr == nil { + // The internal buffer size may need to be the sum of the maximum segment + // size of the two encoders! + addTest(tt, mkChain(tc.t, 2*tc.dstSize, rleEncode{})) + addTest(tt, mkChain(tc.t, tc.dstSize, Nop, 101, rleEncode{})) + addTest(tt, mkChain(Nop, tc.srcSize, tc.t, tc.dstSize, Nop, 100, rleEncode{})) + addTest(tt, mkChain(Nop, tc.srcSize, tc.t, tc.dstSize, Nop, 200, rleEncode{}, 100, Nop)) + } + } + for _, tc := range tests { + str, iter, err := doTransform(tc) + mi := tc.wantIter != 0 && tc.wantIter != iter + if str != tc.wantStr || err != tc.wantErr || mi { + t.Errorf("%s:\ngot iter:%d, %q, %v\nwant iter:%d, %q, %v", tc, iter, str, err, tc.wantIter, tc.wantStr, tc.wantErr) + } + break + } +} + +func TestRemoveFunc(t *testing.T) { + filter := RemoveFunc(func(r rune) bool { + return strings.IndexRune("ab\u0300\u1234,", r) != -1 + }) + tests := []testCase{ + { + src: ",", + wantStr: "", + }, + + { + src: "c", + wantStr: "c", + }, + + { + src: "\u2345", + wantStr: "\u2345", + }, + + { + src: "tschüß", + wantStr: "tschüß", + }, + + { + src: ",до,свидания,", + wantStr: "досвидания", + }, + + { + src: "a\xbd\xb2=\xbc ⌘", + wantStr: "\uFFFD\uFFFD=\uFFFD ⌘", + }, + + { + // If we didn't replace illegal bytes with RuneError, the result + // would be \u0300 or the code would need to be more complex. + src: "\xcc\u0300\x80", + wantStr: "\uFFFD\uFFFD", + }, + + { + src: "\xcc\u0300\x80", + dstSize: 3, + wantStr: "\uFFFD\uFFFD", + wantIter: 2, + }, + + { + src: "\u2345", + dstSize: 2, + wantStr: "", + wantErr: ErrShortDst, + }, + + { + src: "\xcc", + dstSize: 2, + wantStr: "", + wantErr: ErrShortDst, + }, + + { + src: "\u0300", + dstSize: 2, + srcSize: 1, + wantStr: "", + wantErr: ErrShortSrc, + }, + + { + t: RemoveFunc(func(r rune) bool { + return r == utf8.RuneError + }), + src: "\xcc\u0300\x80", + wantStr: "\u0300", + }, + } + + for _, tc := range tests { + tc.desc = tc.src + if tc.t == nil { + tc.t = filter + } + if tc.dstSize == 0 { + tc.dstSize = 100 + } + if tc.srcSize == 0 { + tc.srcSize = 100 + } + str, iter, err := doTransform(tc) + mi := tc.wantIter != 0 && tc.wantIter != iter + if str != tc.wantStr || err != tc.wantErr || mi { + t.Errorf("%+q:\ngot iter:%d, %+q, %v\nwant iter:%d, %+q, %v", tc.src, iter, str, err, tc.wantIter, tc.wantStr, tc.wantErr) + } + + tc.src = str + idem, _, _ := doTransform(tc) + if str != idem { + t.Errorf("%+q: found %+q; want %+q", tc.src, idem, str) + } + } +} + +func TestBytes(t *testing.T) { + for _, tt := range append(testCases, chainTests()...) { + if tt.desc == "allowStutter = true" { + // We don't have control over the buffer size, so we eliminate tests + // that depend on a specific buffer size being set. + continue + } + got := Bytes(tt.t, []byte(tt.src)) + if tt.wantErr != nil { + if tt.wantErr != ErrShortDst && tt.wantErr != ErrShortSrc { + // Bytes should return nil for non-recoverable errors. + if g, w := (got == nil), (tt.wantErr != nil); g != w { + t.Errorf("%s:error: got %v; want %v", tt.desc, g, w) + } + } + // The output strings in the tests that expect an error will + // almost certainly not be the same as the result of Bytes. + continue + } + if string(got) != tt.wantStr { + t.Errorf("%s:string: got %q; want %q", tt.desc, got, tt.wantStr) + } + } +} diff --git a/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/Makefile b/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/Makefile new file mode 100644 index 000000000..d8b8e3596 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/Makefile @@ -0,0 +1,30 @@ +# Copyright 2011 The Go Authors. All rights reserved. +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. + +maketables: maketables.go triegen.go + go build $^ + +maketesttables: maketesttables.go triegen.go + go build $^ + +normregtest: normregtest.go + go build $^ + +tables: maketables + ./maketables > tables.go + gofmt -w tables.go + +trietesttables: maketesttables + ./maketesttables > triedata_test.go + gofmt -w triedata_test.go + +# Downloads from www.unicode.org, so not part +# of standard test scripts. +test: testtables regtest + +testtables: maketables + ./maketables -test > data_test.go && go test -tags=test + +regtest: normregtest + ./normregtest diff --git a/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/composition.go b/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/composition.go new file mode 100644 index 000000000..d17b278ad --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/composition.go @@ -0,0 +1,514 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package norm + +import "unicode/utf8" + +const ( + maxNonStarters = 30 + // The maximum number of characters needed for a buffer is + // maxNonStarters + 1 for the starter + 1 for the GCJ + maxBufferSize = maxNonStarters + 2 + maxNFCExpansion = 3 // NFC(0x1D160) + maxNFKCExpansion = 18 // NFKC(0xFDFA) + + maxByteBufferSize = utf8.UTFMax * maxBufferSize // 128 +) + +// ssState is used for reporting the segment state after inserting a rune. +// It is returned by streamSafe.next. +type ssState int + +const ( + // Indicates a rune was successfully added to the segment. + ssSuccess ssState = iota + // Indicates a rune starts a new segment and should not be added. + ssStarter + // Indicates a rune caused a segment overflow and a CGJ should be inserted. + ssOverflow +) + +// streamSafe implements the policy of when a CGJ should be inserted. +type streamSafe uint8 + +// mkStreamSafe is a shorthand for declaring a streamSafe var and calling +// first on it. +func mkStreamSafe(p Properties) streamSafe { + return streamSafe(p.nTrailingNonStarters()) +} + +// first inserts the first rune of a segment. +func (ss *streamSafe) first(p Properties) { + if *ss != 0 { + panic("!= 0") + } + *ss = streamSafe(p.nTrailingNonStarters()) +} + +// insert returns a ssState value to indicate whether a rune represented by p +// can be inserted. +func (ss *streamSafe) next(p Properties) ssState { + if *ss > maxNonStarters { + panic("streamSafe was not reset") + } + n := p.nLeadingNonStarters() + if *ss += streamSafe(n); *ss > maxNonStarters { + *ss = 0 + return ssOverflow + } + // The Stream-Safe Text Processing prescribes that the counting can stop + // as soon as a starter is encountered. However, there are some starters, + // like Jamo V and T, that can combine with other runes, leaving their + // successive non-starters appended to the previous, possibly causing an + // overflow. We will therefore consider any rune with a non-zero nLead to + // be a non-starter. Note that it always hold that if nLead > 0 then + // nLead == nTrail. + if n == 0 { + *ss = 0 + return ssStarter + } + return ssSuccess +} + +// backwards is used for checking for overflow and segment starts +// when traversing a string backwards. Users do not need to call first +// for the first rune. The state of the streamSafe retains the count of +// the non-starters loaded. +func (ss *streamSafe) backwards(p Properties) ssState { + if *ss > maxNonStarters { + panic("streamSafe was not reset") + } + c := *ss + streamSafe(p.nTrailingNonStarters()) + if c > maxNonStarters { + return ssOverflow + } + *ss = c + if p.nLeadingNonStarters() == 0 { + return ssStarter + } + return ssSuccess +} + +func (ss streamSafe) isMax() bool { + return ss == maxNonStarters +} + +// GraphemeJoiner is inserted after maxNonStarters non-starter runes. +const GraphemeJoiner = "\u034F" + +// reorderBuffer is used to normalize a single segment. Characters inserted with +// insert are decomposed and reordered based on CCC. The compose method can +// be used to recombine characters. Note that the byte buffer does not hold +// the UTF-8 characters in order. Only the rune array is maintained in sorted +// order. flush writes the resulting segment to a byte array. +type reorderBuffer struct { + rune [maxBufferSize]Properties // Per character info. + byte [maxByteBufferSize]byte // UTF-8 buffer. Referenced by runeInfo.pos. + nbyte uint8 // Number or bytes. + ss streamSafe // For limiting length of non-starter sequence. + nrune int // Number of runeInfos. + f formInfo + + src input + nsrc int + tmpBytes input + + out []byte + flushF func(*reorderBuffer) bool +} + +func (rb *reorderBuffer) init(f Form, src []byte) { + rb.f = *formTable[f] + rb.src.setBytes(src) + rb.nsrc = len(src) + rb.ss = 0 +} + +func (rb *reorderBuffer) initString(f Form, src string) { + rb.f = *formTable[f] + rb.src.setString(src) + rb.nsrc = len(src) + rb.ss = 0 +} + +func (rb *reorderBuffer) setFlusher(out []byte, f func(*reorderBuffer) bool) { + rb.out = out + rb.flushF = f +} + +// reset discards all characters from the buffer. +func (rb *reorderBuffer) reset() { + rb.nrune = 0 + rb.nbyte = 0 + rb.ss = 0 +} + +func (rb *reorderBuffer) doFlush() bool { + if rb.f.composing { + rb.compose() + } + res := rb.flushF(rb) + rb.reset() + return res +} + +// appendFlush appends the normalized segment to rb.out. +func appendFlush(rb *reorderBuffer) bool { + for i := 0; i < rb.nrune; i++ { + start := rb.rune[i].pos + end := start + rb.rune[i].size + rb.out = append(rb.out, rb.byte[start:end]...) + } + return true +} + +// flush appends the normalized segment to out and resets rb. +func (rb *reorderBuffer) flush(out []byte) []byte { + for i := 0; i < rb.nrune; i++ { + start := rb.rune[i].pos + end := start + rb.rune[i].size + out = append(out, rb.byte[start:end]...) + } + rb.reset() + return out +} + +// flushCopy copies the normalized segment to buf and resets rb. +// It returns the number of bytes written to buf. +func (rb *reorderBuffer) flushCopy(buf []byte) int { + p := 0 + for i := 0; i < rb.nrune; i++ { + runep := rb.rune[i] + p += copy(buf[p:], rb.byte[runep.pos:runep.pos+runep.size]) + } + rb.reset() + return p +} + +// insertOrdered inserts a rune in the buffer, ordered by Canonical Combining Class. +// It returns false if the buffer is not large enough to hold the rune. +// It is used internally by insert and insertString only. +func (rb *reorderBuffer) insertOrdered(info Properties) { + n := rb.nrune + b := rb.rune[:] + cc := info.ccc + if cc > 0 { + // Find insertion position + move elements to make room. + for ; n > 0; n-- { + if b[n-1].ccc <= cc { + break + } + b[n] = b[n-1] + } + } + rb.nrune += 1 + pos := uint8(rb.nbyte) + rb.nbyte += utf8.UTFMax + info.pos = pos + b[n] = info +} + +// insertErr is an error code returned by insert. Using this type instead +// of error improves performance up to 20% for many of the benchmarks. +type insertErr int + +const ( + iSuccess insertErr = -iota + iShortDst + iShortSrc +) + +// insertFlush inserts the given rune in the buffer ordered by CCC. +// If a decomposition with multiple segments are encountered, they leading +// ones are flushed. +// It returns a non-zero error code if the rune was not inserted. +func (rb *reorderBuffer) insertFlush(src input, i int, info Properties) insertErr { + if rune := src.hangul(i); rune != 0 { + rb.decomposeHangul(rune) + return iSuccess + } + if info.hasDecomposition() { + return rb.insertDecomposed(info.Decomposition()) + } + rb.insertSingle(src, i, info) + return iSuccess +} + +// insertUnsafe inserts the given rune in the buffer ordered by CCC. +// It is assumed there is sufficient space to hold the runes. It is the +// responsibility of the caller to ensure this. This can be done by checking +// the state returned by the streamSafe type. +func (rb *reorderBuffer) insertUnsafe(src input, i int, info Properties) { + if rune := src.hangul(i); rune != 0 { + rb.decomposeHangul(rune) + } + if info.hasDecomposition() { + // TODO: inline. + rb.insertDecomposed(info.Decomposition()) + } else { + rb.insertSingle(src, i, info) + } +} + +// insertDecomposed inserts an entry in to the reorderBuffer for each rune +// in dcomp. dcomp must be a sequence of decomposed UTF-8-encoded runes. +// It flushes the buffer on each new segment start. +func (rb *reorderBuffer) insertDecomposed(dcomp []byte) insertErr { + rb.tmpBytes.setBytes(dcomp) + for i := 0; i < len(dcomp); { + info := rb.f.info(rb.tmpBytes, i) + if info.BoundaryBefore() && rb.nrune > 0 && !rb.doFlush() { + return iShortDst + } + i += copy(rb.byte[rb.nbyte:], dcomp[i:i+int(info.size)]) + rb.insertOrdered(info) + } + return iSuccess +} + +// insertSingle inserts an entry in the reorderBuffer for the rune at +// position i. info is the runeInfo for the rune at position i. +func (rb *reorderBuffer) insertSingle(src input, i int, info Properties) { + src.copySlice(rb.byte[rb.nbyte:], i, i+int(info.size)) + rb.insertOrdered(info) +} + +// insertCGJ inserts a Combining Grapheme Joiner (0x034f) into rb. +func (rb *reorderBuffer) insertCGJ() { + rb.insertSingle(input{str: GraphemeJoiner}, 0, Properties{size: uint8(len(GraphemeJoiner))}) +} + +// appendRune inserts a rune at the end of the buffer. It is used for Hangul. +func (rb *reorderBuffer) appendRune(r rune) { + bn := rb.nbyte + sz := utf8.EncodeRune(rb.byte[bn:], rune(r)) + rb.nbyte += utf8.UTFMax + rb.rune[rb.nrune] = Properties{pos: bn, size: uint8(sz)} + rb.nrune++ +} + +// assignRune sets a rune at position pos. It is used for Hangul and recomposition. +func (rb *reorderBuffer) assignRune(pos int, r rune) { + bn := rb.rune[pos].pos + sz := utf8.EncodeRune(rb.byte[bn:], rune(r)) + rb.rune[pos] = Properties{pos: bn, size: uint8(sz)} +} + +// runeAt returns the rune at position n. It is used for Hangul and recomposition. +func (rb *reorderBuffer) runeAt(n int) rune { + inf := rb.rune[n] + r, _ := utf8.DecodeRune(rb.byte[inf.pos : inf.pos+inf.size]) + return r +} + +// bytesAt returns the UTF-8 encoding of the rune at position n. +// It is used for Hangul and recomposition. +func (rb *reorderBuffer) bytesAt(n int) []byte { + inf := rb.rune[n] + return rb.byte[inf.pos : int(inf.pos)+int(inf.size)] +} + +// For Hangul we combine algorithmically, instead of using tables. +const ( + hangulBase = 0xAC00 // UTF-8(hangulBase) -> EA B0 80 + hangulBase0 = 0xEA + hangulBase1 = 0xB0 + hangulBase2 = 0x80 + + hangulEnd = hangulBase + jamoLVTCount // UTF-8(0xD7A4) -> ED 9E A4 + hangulEnd0 = 0xED + hangulEnd1 = 0x9E + hangulEnd2 = 0xA4 + + jamoLBase = 0x1100 // UTF-8(jamoLBase) -> E1 84 00 + jamoLBase0 = 0xE1 + jamoLBase1 = 0x84 + jamoLEnd = 0x1113 + jamoVBase = 0x1161 + jamoVEnd = 0x1176 + jamoTBase = 0x11A7 + jamoTEnd = 0x11C3 + + jamoTCount = 28 + jamoVCount = 21 + jamoVTCount = 21 * 28 + jamoLVTCount = 19 * 21 * 28 +) + +const hangulUTF8Size = 3 + +func isHangul(b []byte) bool { + if len(b) < hangulUTF8Size { + return false + } + b0 := b[0] + if b0 < hangulBase0 { + return false + } + b1 := b[1] + switch { + case b0 == hangulBase0: + return b1 >= hangulBase1 + case b0 < hangulEnd0: + return true + case b0 > hangulEnd0: + return false + case b1 < hangulEnd1: + return true + } + return b1 == hangulEnd1 && b[2] < hangulEnd2 +} + +func isHangulString(b string) bool { + if len(b) < hangulUTF8Size { + return false + } + b0 := b[0] + if b0 < hangulBase0 { + return false + } + b1 := b[1] + switch { + case b0 == hangulBase0: + return b1 >= hangulBase1 + case b0 < hangulEnd0: + return true + case b0 > hangulEnd0: + return false + case b1 < hangulEnd1: + return true + } + return b1 == hangulEnd1 && b[2] < hangulEnd2 +} + +// Caller must ensure len(b) >= 2. +func isJamoVT(b []byte) bool { + // True if (rune & 0xff00) == jamoLBase + return b[0] == jamoLBase0 && (b[1]&0xFC) == jamoLBase1 +} + +func isHangulWithoutJamoT(b []byte) bool { + c, _ := utf8.DecodeRune(b) + c -= hangulBase + return c < jamoLVTCount && c%jamoTCount == 0 +} + +// decomposeHangul writes the decomposed Hangul to buf and returns the number +// of bytes written. len(buf) should be at least 9. +func decomposeHangul(buf []byte, r rune) int { + const JamoUTF8Len = 3 + r -= hangulBase + x := r % jamoTCount + r /= jamoTCount + utf8.EncodeRune(buf, jamoLBase+r/jamoVCount) + utf8.EncodeRune(buf[JamoUTF8Len:], jamoVBase+r%jamoVCount) + if x != 0 { + utf8.EncodeRune(buf[2*JamoUTF8Len:], jamoTBase+x) + return 3 * JamoUTF8Len + } + return 2 * JamoUTF8Len +} + +// decomposeHangul algorithmically decomposes a Hangul rune into +// its Jamo components. +// See http://unicode.org/reports/tr15/#Hangul for details on decomposing Hangul. +func (rb *reorderBuffer) decomposeHangul(r rune) { + r -= hangulBase + x := r % jamoTCount + r /= jamoTCount + rb.appendRune(jamoLBase + r/jamoVCount) + rb.appendRune(jamoVBase + r%jamoVCount) + if x != 0 { + rb.appendRune(jamoTBase + x) + } +} + +// combineHangul algorithmically combines Jamo character components into Hangul. +// See http://unicode.org/reports/tr15/#Hangul for details on combining Hangul. +func (rb *reorderBuffer) combineHangul(s, i, k int) { + b := rb.rune[:] + bn := rb.nrune + for ; i < bn; i++ { + cccB := b[k-1].ccc + cccC := b[i].ccc + if cccB == 0 { + s = k - 1 + } + if s != k-1 && cccB >= cccC { + // b[i] is blocked by greater-equal cccX below it + b[k] = b[i] + k++ + } else { + l := rb.runeAt(s) // also used to compare to hangulBase + v := rb.runeAt(i) // also used to compare to jamoT + switch { + case jamoLBase <= l && l < jamoLEnd && + jamoVBase <= v && v < jamoVEnd: + // 11xx plus 116x to LV + rb.assignRune(s, hangulBase+ + (l-jamoLBase)*jamoVTCount+(v-jamoVBase)*jamoTCount) + case hangulBase <= l && l < hangulEnd && + jamoTBase < v && v < jamoTEnd && + ((l-hangulBase)%jamoTCount) == 0: + // ACxx plus 11Ax to LVT + rb.assignRune(s, l+v-jamoTBase) + default: + b[k] = b[i] + k++ + } + } + } + rb.nrune = k +} + +// compose recombines the runes in the buffer. +// It should only be used to recompose a single segment, as it will not +// handle alternations between Hangul and non-Hangul characters correctly. +func (rb *reorderBuffer) compose() { + // UAX #15, section X5 , including Corrigendum #5 + // "In any character sequence beginning with starter S, a character C is + // blocked from S if and only if there is some character B between S + // and C, and either B is a starter or it has the same or higher + // combining class as C." + bn := rb.nrune + if bn == 0 { + return + } + k := 1 + b := rb.rune[:] + for s, i := 0, 1; i < bn; i++ { + if isJamoVT(rb.bytesAt(i)) { + // Redo from start in Hangul mode. Necessary to support + // U+320E..U+321E in NFKC mode. + rb.combineHangul(s, i, k) + return + } + ii := b[i] + // We can only use combineForward as a filter if we later + // get the info for the combined character. This is more + // expensive than using the filter. Using combinesBackward() + // is safe. + if ii.combinesBackward() { + cccB := b[k-1].ccc + cccC := ii.ccc + blocked := false // b[i] blocked by starter or greater or equal CCC? + if cccB == 0 { + s = k - 1 + } else { + blocked = s != k-1 && cccB >= cccC + } + if !blocked { + combined := combine(rb.runeAt(s), rb.runeAt(i)) + if combined != 0 { + rb.assignRune(s, combined) + continue + } + } + } + b[k] = b[i] + k++ + } + rb.nrune = k +} diff --git a/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/composition_test.go b/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/composition_test.go new file mode 100644 index 000000000..11684069d --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/composition_test.go @@ -0,0 +1,130 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package norm + +import "testing" + +// TestCase is used for most tests. +type TestCase struct { + in []rune + out []rune +} + +func runTests(t *testing.T, name string, fm Form, tests []TestCase) { + rb := reorderBuffer{} + rb.init(fm, nil) + for i, test := range tests { + rb.setFlusher(nil, appendFlush) + for j, rune := range test.in { + b := []byte(string(rune)) + src := inputBytes(b) + info := rb.f.info(src, 0) + if j == 0 { + rb.ss.first(info) + } else { + rb.ss.next(info) + } + if rb.insertFlush(src, 0, info) < 0 { + t.Errorf("%s:%d: insert failed for rune %d", name, i, j) + } + } + rb.doFlush() + was := string(rb.out) + want := string(test.out) + if len(was) != len(want) { + t.Errorf("%s:%d: length = %d; want %d", name, i, len(was), len(want)) + } + if was != want { + k, pfx := pidx(was, want) + t.Errorf("%s:%d: \nwas %s%+q; \nwant %s%+q", name, i, pfx, was[k:], pfx, want[k:]) + } + } +} + +func TestFlush(t *testing.T) { + const ( + hello = "Hello " + world = "world!" + ) + buf := make([]byte, maxByteBufferSize) + p := copy(buf, hello) + out := buf[p:] + rb := reorderBuffer{} + rb.initString(NFC, world) + if i := rb.flushCopy(out); i != 0 { + t.Errorf("wrote bytes on flush of empty buffer. (len(out) = %d)", i) + } + + for i := range world { + // No need to set streamSafe values for this test. + rb.insertFlush(rb.src, i, rb.f.info(rb.src, i)) + n := rb.flushCopy(out) + out = out[n:] + p += n + } + + was := buf[:p] + want := hello + world + if string(was) != want { + t.Errorf(`output after flush was "%s"; want "%s"`, string(was), want) + } + if rb.nrune != 0 { + t.Errorf("non-null size of info buffer (rb.nrune == %d)", rb.nrune) + } + if rb.nbyte != 0 { + t.Errorf("non-null size of byte buffer (rb.nbyte == %d)", rb.nbyte) + } +} + +var insertTests = []TestCase{ + {[]rune{'a'}, []rune{'a'}}, + {[]rune{0x300}, []rune{0x300}}, + {[]rune{0x300, 0x316}, []rune{0x316, 0x300}}, // CCC(0x300)==230; CCC(0x316)==220 + {[]rune{0x316, 0x300}, []rune{0x316, 0x300}}, + {[]rune{0x41, 0x316, 0x300}, []rune{0x41, 0x316, 0x300}}, + {[]rune{0x41, 0x300, 0x316}, []rune{0x41, 0x316, 0x300}}, + {[]rune{0x300, 0x316, 0x41}, []rune{0x316, 0x300, 0x41}}, + {[]rune{0x41, 0x300, 0x40, 0x316}, []rune{0x41, 0x300, 0x40, 0x316}}, +} + +func TestInsert(t *testing.T) { + runTests(t, "TestInsert", NFD, insertTests) +} + +var decompositionNFDTest = []TestCase{ + {[]rune{0xC0}, []rune{0x41, 0x300}}, + {[]rune{0xAC00}, []rune{0x1100, 0x1161}}, + {[]rune{0x01C4}, []rune{0x01C4}}, + {[]rune{0x320E}, []rune{0x320E}}, + {[]rune("음ẻ과"), []rune{0x110B, 0x1173, 0x11B7, 0x65, 0x309, 0x1100, 0x116A}}, +} + +var decompositionNFKDTest = []TestCase{ + {[]rune{0xC0}, []rune{0x41, 0x300}}, + {[]rune{0xAC00}, []rune{0x1100, 0x1161}}, + {[]rune{0x01C4}, []rune{0x44, 0x5A, 0x030C}}, + {[]rune{0x320E}, []rune{0x28, 0x1100, 0x1161, 0x29}}, +} + +func TestDecomposition(t *testing.T) { + runTests(t, "TestDecompositionNFD", NFD, decompositionNFDTest) + runTests(t, "TestDecompositionNFKD", NFKD, decompositionNFKDTest) +} + +var compositionTest = []TestCase{ + {[]rune{0x41, 0x300}, []rune{0xC0}}, + {[]rune{0x41, 0x316}, []rune{0x41, 0x316}}, + {[]rune{0x41, 0x300, 0x35D}, []rune{0xC0, 0x35D}}, + {[]rune{0x41, 0x316, 0x300}, []rune{0xC0, 0x316}}, + // blocking starter + {[]rune{0x41, 0x316, 0x40, 0x300}, []rune{0x41, 0x316, 0x40, 0x300}}, + {[]rune{0x1100, 0x1161}, []rune{0xAC00}}, + // parenthesized Hangul, alternate between ASCII and Hangul. + {[]rune{0x28, 0x1100, 0x1161, 0x29}, []rune{0x28, 0xAC00, 0x29}}, +} + +func TestComposition(t *testing.T) { + runTests(t, "TestComposition", NFC, compositionTest) +} diff --git a/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/example_iter_test.go b/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/example_iter_test.go new file mode 100644 index 000000000..280361a4d --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/example_iter_test.go @@ -0,0 +1,82 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package norm_test + +import ( + "bytes" + "fmt" + "unicode/utf8" + + "code.google.com/p/go.text/unicode/norm" +) + +// EqualSimple uses a norm.Iter to compare two non-normalized +// strings for equivalence. +func EqualSimple(a, b string) bool { + var ia, ib norm.Iter + ia.InitString(norm.NFKD, a) + ib.InitString(norm.NFKD, b) + for !ia.Done() && !ib.Done() { + if !bytes.Equal(ia.Next(), ib.Next()) { + return false + } + } + return ia.Done() && ib.Done() +} + +// FindPrefix finds the longest common prefix of ASCII characters +// of a and b. +func FindPrefix(a, b string) int { + i := 0 + for ; i < len(a) && i < len(b) && a[i] < utf8.RuneSelf && a[i] == b[i]; i++ { + } + return i +} + +// EqualOpt is like EqualSimple, but optimizes the special +// case for ASCII characters. +func EqualOpt(a, b string) bool { + n := FindPrefix(a, b) + a, b = a[n:], b[n:] + var ia, ib norm.Iter + ia.InitString(norm.NFKD, a) + ib.InitString(norm.NFKD, b) + for !ia.Done() && !ib.Done() { + if !bytes.Equal(ia.Next(), ib.Next()) { + return false + } + if n := int64(FindPrefix(a[ia.Pos():], b[ib.Pos():])); n != 0 { + ia.Seek(n, 1) + ib.Seek(n, 1) + } + } + return ia.Done() && ib.Done() +} + +var compareTests = []struct{ a, b string }{ + {"aaa", "aaa"}, + {"aaa", "aab"}, + {"a\u0300a", "\u00E0a"}, + {"a\u0300\u0320b", "a\u0320\u0300b"}, + {"\u1E0A\u0323", "\x44\u0323\u0307"}, + // A character that decomposes into multiple segments + // spans several iterations. + {"\u3304", "\u30A4\u30CB\u30F3\u30AF\u3099"}, +} + +func ExampleIter() { + for i, t := range compareTests { + r0 := EqualSimple(t.a, t.b) + r1 := EqualOpt(t.a, t.b) + fmt.Printf("%d: %v %v\n", i, r0, r1) + } + // Output: + // 0: true true + // 1: false false + // 2: true true + // 3: true true + // 4: true true + // 5: true true +} diff --git a/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/forminfo.go b/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/forminfo.go new file mode 100644 index 000000000..dee232ff4 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/forminfo.go @@ -0,0 +1,256 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package norm + +// This file contains Form-specific logic and wrappers for data in tables.go. + +// Rune info is stored in a separate trie per composing form. A composing form +// and its corresponding decomposing form share the same trie. Each trie maps +// a rune to a uint16. The values take two forms. For v >= 0x8000: +// bits +// 15: 1 (inverse of NFD_QD bit of qcInfo) +// 13..7: qcInfo (see below). isYesD is always true (no decompostion). +// 6..0: ccc (compressed CCC value). +// For v < 0x8000, the respective rune has a decomposition and v is an index +// into a byte array of UTF-8 decomposition sequences and additional info and +// has the form: +//
* [ []] +// The header contains the number of bytes in the decomposition (excluding this +// length byte). The two most significant bits of this length byte correspond +// to bit 5 and 4 of qcInfo (see below). The byte sequence itself starts at v+1. +// The byte sequence is followed by a trailing and leading CCC if the values +// for these are not zero. The value of v determines which ccc are appended +// to the sequences. For v < firstCCC, there are none, for v >= firstCCC, +// the sequence is followed by a trailing ccc, and for v >= firstLeadingCC +// there is an additional leading ccc. The value of tccc itself is the +// trailing CCC shifted left 2 bits. The two least-significant bits of tccc +// are the number of trailing non-starters. + +const ( + qcInfoMask = 0x3F // to clear all but the relevant bits in a qcInfo + headerLenMask = 0x3F // extract the length value from the header byte + headerFlagsMask = 0xC0 // extract the qcInfo bits from the header byte +) + +// Properties provides access to normalization properties of a rune. +type Properties struct { + pos uint8 // start position in reorderBuffer; used in composition.go + size uint8 // length of UTF-8 encoding of this rune + ccc uint8 // leading canonical combining class (ccc if not decomposition) + tccc uint8 // trailing canonical combining class (ccc if not decomposition) + nLead uint8 // number of leading non-starters. + flags qcInfo // quick check flags + index uint16 +} + +// functions dispatchable per form +type lookupFunc func(b input, i int) Properties + +// formInfo holds Form-specific functions and tables. +type formInfo struct { + form Form + composing, compatibility bool // form type + info lookupFunc + nextMain iterFunc +} + +var formTable []*formInfo + +func init() { + formTable = make([]*formInfo, 4) + + for i := range formTable { + f := &formInfo{} + formTable[i] = f + f.form = Form(i) + if Form(i) == NFKD || Form(i) == NFKC { + f.compatibility = true + f.info = lookupInfoNFKC + } else { + f.info = lookupInfoNFC + } + f.nextMain = nextDecomposed + if Form(i) == NFC || Form(i) == NFKC { + f.nextMain = nextComposed + f.composing = true + } + } +} + +// We do not distinguish between boundaries for NFC, NFD, etc. to avoid +// unexpected behavior for the user. For example, in NFD, there is a boundary +// after 'a'. However, 'a' might combine with modifiers, so from the application's +// perspective it is not a good boundary. We will therefore always use the +// boundaries for the combining variants. + +// BoundaryBefore returns true if this rune starts a new segment and +// cannot combine with any rune on the left. +func (p Properties) BoundaryBefore() bool { + if p.ccc == 0 && !p.combinesBackward() { + return true + } + // We assume that the CCC of the first character in a decomposition + // is always non-zero if different from info.ccc and that we can return + // false at this point. This is verified by maketables. + return false +} + +// BoundaryAfter returns true if runes cannot combine with or otherwise +// interact with this or previous runes. +func (p Properties) BoundaryAfter() bool { + // TODO: loosen these conditions. + return p.isInert() +} + +// We pack quick check data in 4 bits: +// 5: Combines forward (0 == false, 1 == true) +// 4..3: NFC_QC Yes(00), No (10), or Maybe (11) +// 2: NFD_QC Yes (0) or No (1). No also means there is a decomposition. +// 1..0: Number of trailing non-starters. +// +// When all 4 bits are zero, the character is inert, meaning it is never +// influenced by normalization. +type qcInfo uint8 + +func (p Properties) isYesC() bool { return p.flags&0x10 == 0 } +func (p Properties) isYesD() bool { return p.flags&0x4 == 0 } + +func (p Properties) combinesForward() bool { return p.flags&0x20 != 0 } +func (p Properties) combinesBackward() bool { return p.flags&0x8 != 0 } // == isMaybe +func (p Properties) hasDecomposition() bool { return p.flags&0x4 != 0 } // == isNoD + +func (p Properties) isInert() bool { + return p.flags&qcInfoMask == 0 && p.ccc == 0 +} + +func (p Properties) multiSegment() bool { + return p.index >= firstMulti && p.index < endMulti +} + +func (p Properties) nLeadingNonStarters() uint8 { + return p.nLead +} + +func (p Properties) nTrailingNonStarters() uint8 { + return uint8(p.flags & 0x03) +} + +// Decomposition returns the decomposition for the underlying rune +// or nil if there is none. +func (p Properties) Decomposition() []byte { + // TODO: create the decomposition for Hangul? + if p.index == 0 { + return nil + } + i := p.index + n := decomps[i] & headerLenMask + i++ + return decomps[i : i+uint16(n)] +} + +// Size returns the length of UTF-8 encoding of the rune. +func (p Properties) Size() int { + return int(p.size) +} + +// CCC returns the canonical combining class of the underlying rune. +func (p Properties) CCC() uint8 { + if p.index >= firstCCCZeroExcept { + return 0 + } + return ccc[p.ccc] +} + +// LeadCCC returns the CCC of the first rune in the decomposition. +// If there is no decomposition, LeadCCC equals CCC. +func (p Properties) LeadCCC() uint8 { + return ccc[p.ccc] +} + +// TrailCCC returns the CCC of the last rune in the decomposition. +// If there is no decomposition, TrailCCC equals CCC. +func (p Properties) TrailCCC() uint8 { + return ccc[p.tccc] +} + +// Recomposition +// We use 32-bit keys instead of 64-bit for the two codepoint keys. +// This clips off the bits of three entries, but we know this will not +// result in a collision. In the unlikely event that changes to +// UnicodeData.txt introduce collisions, the compiler will catch it. +// Note that the recomposition map for NFC and NFKC are identical. + +// combine returns the combined rune or 0 if it doesn't exist. +func combine(a, b rune) rune { + key := uint32(uint16(a))<<16 + uint32(uint16(b)) + return recompMap[key] +} + +func lookupInfoNFC(b input, i int) Properties { + v, sz := b.charinfoNFC(i) + return compInfo(v, sz) +} + +func lookupInfoNFKC(b input, i int) Properties { + v, sz := b.charinfoNFKC(i) + return compInfo(v, sz) +} + +// Properties returns properties for the first rune in s. +func (f Form) Properties(s []byte) Properties { + if f == NFC || f == NFD { + return compInfo(nfcTrie.lookup(s)) + } + return compInfo(nfkcTrie.lookup(s)) +} + +// PropertiesString returns properties for the first rune in s. +func (f Form) PropertiesString(s string) Properties { + if f == NFC || f == NFD { + return compInfo(nfcTrie.lookupString(s)) + } + return compInfo(nfkcTrie.lookupString(s)) +} + +// compInfo converts the information contained in v and sz +// to a Properties. See the comment at the top of the file +// for more information on the format. +func compInfo(v uint16, sz int) Properties { + if v == 0 { + return Properties{size: uint8(sz)} + } else if v >= 0x8000 { + p := Properties{ + size: uint8(sz), + ccc: uint8(v), + tccc: uint8(v), + flags: qcInfo(v >> 8), + } + if p.ccc > 0 || p.combinesBackward() { + p.nLead = uint8(p.flags & 0x3) + } + return p + } + // has decomposition + h := decomps[v] + f := (qcInfo(h&headerFlagsMask) >> 2) | 0x4 + p := Properties{size: uint8(sz), flags: f, index: v} + if v >= firstCCC { + v += uint16(h&headerLenMask) + 1 + c := decomps[v] + p.tccc = c >> 2 + p.flags |= qcInfo(c & 0x3) + if v >= firstLeadingCCC { + p.nLead = c & 0x3 + if v >= firstStarterWithNLead { + // We were tricked. Remove the decomposition. + p.flags &= 0x03 + p.index = 0 + return p + } + p.ccc = decomps[v+1] + } + } + return p +} diff --git a/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/forminfo_test.go b/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/forminfo_test.go new file mode 100644 index 000000000..e15ba9bee --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/forminfo_test.go @@ -0,0 +1,54 @@ +// 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. + +// +build test + +package norm + +import "testing" + +func TestProperties(t *testing.T) { + var d runeData + CK := [2]string{"C", "K"} + for k, r := 1, rune(0); r < 0x2ffff; r++ { + if k < len(testData) && r == testData[k].r { + d = testData[k] + k++ + } + s := string(r) + for j, p := range []Properties{NFC.PropertiesString(s), NFKC.PropertiesString(s)} { + f := d.f[j] + if p.CCC() != d.ccc { + t.Errorf("%U: ccc(%s): was %d; want %d %X", r, CK[j], p.CCC(), d.ccc, p.index) + } + if p.isYesC() != (f.qc == Yes) { + t.Errorf("%U: YesC(%s): was %v; want %v", r, CK[j], p.isYesC(), f.qc == Yes) + } + if p.combinesBackward() != (f.qc == Maybe) { + t.Errorf("%U: combines backwards(%s): was %v; want %v", r, CK[j], p.combinesBackward(), f.qc == Maybe) + } + if p.nLeadingNonStarters() != d.nLead { + t.Errorf("%U: nLead(%s): was %d; want %d %#v %#v", r, CK[j], p.nLeadingNonStarters(), d.nLead, p, d) + } + if p.nTrailingNonStarters() != d.nTrail { + t.Errorf("%U: nTrail(%s): was %d; want %d %#v %#v", r, CK[j], p.nTrailingNonStarters(), d.nTrail, p, d) + } + if p.combinesForward() != f.combinesForward { + t.Errorf("%U: combines forward(%s): was %v; want %v %#v", r, CK[j], p.combinesForward(), f.combinesForward, p) + } + // Skip Hangul as it is algorithmically computed. + if r >= hangulBase && r < hangulEnd { + continue + } + if p.hasDecomposition() { + if has := f.decomposition != ""; !has { + t.Errorf("%U: hasDecomposition(%s): was %v; want %v", r, CK[j], p.hasDecomposition(), has) + } + if string(p.Decomposition()) != f.decomposition { + t.Errorf("%U: decomp(%s): was %+q; want %+q", r, CK[j], p.Decomposition(), f.decomposition) + } + } + } + } +} diff --git a/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/input.go b/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/input.go new file mode 100644 index 000000000..630b94477 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/input.go @@ -0,0 +1,105 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package norm + +import "unicode/utf8" + +type input struct { + str string + bytes []byte +} + +func inputBytes(str []byte) input { + return input{bytes: str} +} + +func inputString(str string) input { + return input{str: str} +} + +func (in *input) setBytes(str []byte) { + in.str = "" + in.bytes = str +} + +func (in *input) setString(str string) { + in.str = str + in.bytes = nil +} + +func (in *input) _byte(p int) byte { + if in.bytes == nil { + return in.str[p] + } + return in.bytes[p] +} + +func (in *input) skipASCII(p, max int) int { + if in.bytes == nil { + for ; p < max && in.str[p] < utf8.RuneSelf; p++ { + } + } else { + for ; p < max && in.bytes[p] < utf8.RuneSelf; p++ { + } + } + return p +} + +func (in *input) skipContinuationBytes(p int) int { + if in.bytes == nil { + for ; p < len(in.str) && !utf8.RuneStart(in.str[p]); p++ { + } + } else { + for ; p < len(in.bytes) && !utf8.RuneStart(in.bytes[p]); p++ { + } + } + return p +} + +func (in *input) appendSlice(buf []byte, b, e int) []byte { + if in.bytes != nil { + return append(buf, in.bytes[b:e]...) + } + for i := b; i < e; i++ { + buf = append(buf, in.str[i]) + } + return buf +} + +func (in *input) copySlice(buf []byte, b, e int) int { + if in.bytes == nil { + return copy(buf, in.str[b:e]) + } + return copy(buf, in.bytes[b:e]) +} + +func (in *input) charinfoNFC(p int) (uint16, int) { + if in.bytes == nil { + return nfcTrie.lookupString(in.str[p:]) + } + return nfcTrie.lookup(in.bytes[p:]) +} + +func (in *input) charinfoNFKC(p int) (uint16, int) { + if in.bytes == nil { + return nfkcTrie.lookupString(in.str[p:]) + } + return nfkcTrie.lookup(in.bytes[p:]) +} + +func (in *input) hangul(p int) (r rune) { + if in.bytes == nil { + if !isHangulString(in.str[p:]) { + return 0 + } + r, _ = utf8.DecodeRuneInString(in.str[p:]) + } else { + if !isHangul(in.bytes[p:]) { + return 0 + } + r, _ = utf8.DecodeRune(in.bytes[p:]) + } + return r +} diff --git a/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/iter.go b/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/iter.go new file mode 100644 index 000000000..952544c53 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/iter.go @@ -0,0 +1,448 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package norm + +import ( + "fmt" + "unicode/utf8" +) + +const MaxSegmentSize = maxByteBufferSize + +// An Iter iterates over a string or byte slice, while normalizing it +// to a given Form. +type Iter struct { + rb reorderBuffer + buf [maxByteBufferSize]byte + info Properties // first character saved from previous iteration + next iterFunc // implementation of next depends on form + asciiF iterFunc + + p int // current position in input source + multiSeg []byte // remainder of multi-segment decomposition +} + +type iterFunc func(*Iter) []byte + +// Init initializes i to iterate over src after normalizing it to Form f. +func (i *Iter) Init(f Form, src []byte) { + i.p = 0 + if len(src) == 0 { + i.setDone() + i.rb.nsrc = 0 + return + } + i.multiSeg = nil + i.rb.init(f, src) + i.next = i.rb.f.nextMain + i.asciiF = nextASCIIBytes + i.info = i.rb.f.info(i.rb.src, i.p) +} + +// InitString initializes i to iterate over src after normalizing it to Form f. +func (i *Iter) InitString(f Form, src string) { + i.p = 0 + if len(src) == 0 { + i.setDone() + i.rb.nsrc = 0 + return + } + i.multiSeg = nil + i.rb.initString(f, src) + i.next = i.rb.f.nextMain + i.asciiF = nextASCIIString + i.info = i.rb.f.info(i.rb.src, i.p) +} + +// Seek sets the segment to be returned by the next call to Next to start +// at position p. It is the responsibility of the caller to set p to the +// start of a UTF8 rune. +func (i *Iter) Seek(offset int64, whence int) (int64, error) { + var abs int64 + switch whence { + case 0: + abs = offset + case 1: + abs = int64(i.p) + offset + case 2: + abs = int64(i.rb.nsrc) + offset + default: + return 0, fmt.Errorf("norm: invalid whence") + } + if abs < 0 { + return 0, fmt.Errorf("norm: negative position") + } + if int(abs) >= i.rb.nsrc { + i.setDone() + return int64(i.p), nil + } + i.p = int(abs) + i.multiSeg = nil + i.next = i.rb.f.nextMain + i.info = i.rb.f.info(i.rb.src, i.p) + return abs, nil +} + +// returnSlice returns a slice of the underlying input type as a byte slice. +// If the underlying is of type []byte, it will simply return a slice. +// If the underlying is of type string, it will copy the slice to the buffer +// and return that. +func (i *Iter) returnSlice(a, b int) []byte { + if i.rb.src.bytes == nil { + return i.buf[:copy(i.buf[:], i.rb.src.str[a:b])] + } + return i.rb.src.bytes[a:b] +} + +// Pos returns the byte position at which the next call to Next will commence processing. +func (i *Iter) Pos() int { + return i.p +} + +func (i *Iter) setDone() { + i.next = nextDone + i.p = i.rb.nsrc +} + +// Done returns true if there is no more input to process. +func (i *Iter) Done() bool { + return i.p >= i.rb.nsrc +} + +// Next returns f(i.input[i.Pos():n]), where n is a boundary of i.input. +// For any input a and b for which f(a) == f(b), subsequent calls +// to Next will return the same segments. +// Modifying runes are grouped together with the preceding starter, if such a starter exists. +// Although not guaranteed, n will typically be the smallest possible n. +func (i *Iter) Next() []byte { + return i.next(i) +} + +func nextASCIIBytes(i *Iter) []byte { + p := i.p + 1 + if p >= i.rb.nsrc { + i.setDone() + return i.rb.src.bytes[i.p:p] + } + if i.rb.src.bytes[p] < utf8.RuneSelf { + p0 := i.p + i.p = p + return i.rb.src.bytes[p0:p] + } + i.info = i.rb.f.info(i.rb.src, i.p) + i.next = i.rb.f.nextMain + return i.next(i) +} + +func nextASCIIString(i *Iter) []byte { + p := i.p + 1 + if p >= i.rb.nsrc { + i.buf[0] = i.rb.src.str[i.p] + i.setDone() + return i.buf[:1] + } + if i.rb.src.str[p] < utf8.RuneSelf { + i.buf[0] = i.rb.src.str[i.p] + i.p = p + return i.buf[:1] + } + i.info = i.rb.f.info(i.rb.src, i.p) + i.next = i.rb.f.nextMain + return i.next(i) +} + +func nextHangul(i *Iter) []byte { + p := i.p + next := p + hangulUTF8Size + if next >= i.rb.nsrc { + i.setDone() + } else if i.rb.src.hangul(next) == 0 { + i.info = i.rb.f.info(i.rb.src, i.p) + i.next = i.rb.f.nextMain + return i.next(i) + } + i.p = next + return i.buf[:decomposeHangul(i.buf[:], i.rb.src.hangul(p))] +} + +func nextDone(i *Iter) []byte { + return nil +} + +// nextMulti is used for iterating over multi-segment decompositions +// for decomposing normal forms. +func nextMulti(i *Iter) []byte { + j := 0 + d := i.multiSeg + // skip first rune + for j = 1; j < len(d) && !utf8.RuneStart(d[j]); j++ { + } + for j < len(d) { + info := i.rb.f.info(input{bytes: d}, j) + if info.BoundaryBefore() { + i.multiSeg = d[j:] + return d[:j] + } + j += int(info.size) + } + // treat last segment as normal decomposition + i.next = i.rb.f.nextMain + return i.next(i) +} + +// nextMultiNorm is used for iterating over multi-segment decompositions +// for composing normal forms. +func nextMultiNorm(i *Iter) []byte { + j := 0 + d := i.multiSeg + for j < len(d) { + info := i.rb.f.info(input{bytes: d}, j) + if info.BoundaryBefore() { + i.rb.compose() + seg := i.buf[:i.rb.flushCopy(i.buf[:])] + i.rb.ss.first(info) + i.rb.insertUnsafe(input{bytes: d}, j, info) + i.multiSeg = d[j+int(info.size):] + return seg + } + i.rb.ss.next(info) + i.rb.insertUnsafe(input{bytes: d}, j, info) + j += int(info.size) + } + i.multiSeg = nil + i.next = nextComposed + return doNormComposed(i) +} + +// nextDecomposed is the implementation of Next for forms NFD and NFKD. +func nextDecomposed(i *Iter) (next []byte) { + outp := 0 + inCopyStart, outCopyStart := i.p, 0 + ss := mkStreamSafe(i.info) + for { + if sz := int(i.info.size); sz <= 1 { + p := i.p + i.p++ // ASCII or illegal byte. Either way, advance by 1. + if i.p >= i.rb.nsrc { + i.setDone() + return i.returnSlice(p, i.p) + } else if i.rb.src._byte(i.p) < utf8.RuneSelf { + i.next = i.asciiF + return i.returnSlice(p, i.p) + } + outp++ + } else if d := i.info.Decomposition(); d != nil { + // Note: If leading CCC != 0, then len(d) == 2 and last is also non-zero. + // Case 1: there is a leftover to copy. In this case the decomposition + // must begin with a modifier and should always be appended. + // Case 2: no leftover. Simply return d if followed by a ccc == 0 value. + p := outp + len(d) + if outp > 0 { + i.rb.src.copySlice(i.buf[outCopyStart:], inCopyStart, i.p) + if p > len(i.buf) { + return i.buf[:outp] + } + } else if i.info.multiSegment() { + // outp must be 0 as multi-segment decompositions always + // start a new segment. + if i.multiSeg == nil { + i.multiSeg = d + i.next = nextMulti + return nextMulti(i) + } + // We are in the last segment. Treat as normal decomposition. + d = i.multiSeg + i.multiSeg = nil + p = len(d) + } + prevCC := i.info.tccc + if i.p += sz; i.p >= i.rb.nsrc { + i.setDone() + i.info = Properties{} // Force BoundaryBefore to succeed. + } else { + i.info = i.rb.f.info(i.rb.src, i.p) + } + switch ss.next(i.info) { + case ssOverflow: + i.next = nextCGJDecompose + fallthrough + case ssStarter: + if outp > 0 { + copy(i.buf[outp:], d) + return i.buf[:p] + } + return d + } + copy(i.buf[outp:], d) + outp = p + inCopyStart, outCopyStart = i.p, outp + if i.info.ccc < prevCC { + goto doNorm + } + continue + } else if r := i.rb.src.hangul(i.p); r != 0 { + outp = decomposeHangul(i.buf[:], r) + i.p += hangulUTF8Size + inCopyStart, outCopyStart = i.p, outp + if i.p >= i.rb.nsrc { + i.setDone() + break + } else if i.rb.src.hangul(i.p) != 0 { + i.next = nextHangul + return i.buf[:outp] + } + } else { + p := outp + sz + if p > len(i.buf) { + break + } + outp = p + i.p += sz + } + if i.p >= i.rb.nsrc { + i.setDone() + break + } + prevCC := i.info.tccc + i.info = i.rb.f.info(i.rb.src, i.p) + if v := ss.next(i.info); v == ssStarter { + break + } else if v == ssOverflow { + i.next = nextCGJDecompose + break + } + if i.info.ccc < prevCC { + goto doNorm + } + } + if outCopyStart == 0 { + return i.returnSlice(inCopyStart, i.p) + } else if inCopyStart < i.p { + i.rb.src.copySlice(i.buf[outCopyStart:], inCopyStart, i.p) + } + return i.buf[:outp] +doNorm: + // Insert what we have decomposed so far in the reorderBuffer. + // As we will only reorder, there will always be enough room. + i.rb.src.copySlice(i.buf[outCopyStart:], inCopyStart, i.p) + i.rb.insertDecomposed(i.buf[0:outp]) + return doNormDecomposed(i) +} + +func doNormDecomposed(i *Iter) []byte { + for { + if s := i.rb.ss.next(i.info); s == ssOverflow { + i.next = nextCGJDecompose + break + } + i.rb.insertUnsafe(i.rb.src, i.p, i.info) + if i.p += int(i.info.size); i.p >= i.rb.nsrc { + i.setDone() + break + } + i.info = i.rb.f.info(i.rb.src, i.p) + if i.info.ccc == 0 { + break + } + } + // new segment or too many combining characters: exit normalization + return i.buf[:i.rb.flushCopy(i.buf[:])] +} + +func nextCGJDecompose(i *Iter) []byte { + i.rb.ss = 0 + i.rb.insertCGJ() + i.next = nextDecomposed + buf := doNormDecomposed(i) + return buf +} + +// nextComposed is the implementation of Next for forms NFC and NFKC. +func nextComposed(i *Iter) []byte { + outp, startp := 0, i.p + var prevCC uint8 + ss := mkStreamSafe(i.info) + for { + if !i.info.isYesC() { + goto doNorm + } + prevCC = i.info.tccc + sz := int(i.info.size) + if sz == 0 { + sz = 1 // illegal rune: copy byte-by-byte + } + p := outp + sz + if p > len(i.buf) { + break + } + outp = p + i.p += sz + if i.p >= i.rb.nsrc { + i.setDone() + break + } else if i.rb.src._byte(i.p) < utf8.RuneSelf { + i.next = i.asciiF + break + } + i.info = i.rb.f.info(i.rb.src, i.p) + if v := ss.next(i.info); v == ssStarter { + break + } else if v == ssOverflow { + i.next = nextCGJCompose + break + } + if i.info.ccc < prevCC { + goto doNorm + } + } + return i.returnSlice(startp, i.p) +doNorm: + i.p = startp + i.info = i.rb.f.info(i.rb.src, i.p) + if i.info.multiSegment() { + d := i.info.Decomposition() + info := i.rb.f.info(input{bytes: d}, 0) + i.rb.insertUnsafe(input{bytes: d}, 0, info) + i.multiSeg = d[int(info.size):] + i.next = nextMultiNorm + return nextMultiNorm(i) + } + i.rb.ss.first(i.info) + i.rb.insertUnsafe(i.rb.src, i.p, i.info) + return doNormComposed(i) +} + +func doNormComposed(i *Iter) []byte { + // First rune should already be inserted. + for { + if i.p += int(i.info.size); i.p >= i.rb.nsrc { + i.setDone() + break + } + i.info = i.rb.f.info(i.rb.src, i.p) + if s := i.rb.ss.next(i.info); s == ssStarter { + break + } else if s == ssOverflow { + i.next = nextCGJCompose + break + } + i.rb.insertUnsafe(i.rb.src, i.p, i.info) + } + i.rb.compose() + seg := i.buf[:i.rb.flushCopy(i.buf[:])] + return seg +} + +func nextCGJCompose(i *Iter) []byte { + i.rb.ss = 0 // instead of first + i.rb.insertCGJ() + i.next = nextComposed + // Note that we treat any rune with nLeadingNonStarters > 0 as a non-starter, + // even if they are not. This is particularly dubious for U+FF9E and UFF9A. + // If we ever change that, insert a check here. + i.rb.ss.first(i.info) + i.rb.insertUnsafe(i.rb.src, i.p, i.info) + return doNormComposed(i) +} diff --git a/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/iter_test.go b/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/iter_test.go new file mode 100644 index 000000000..e2aa6f251 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/iter_test.go @@ -0,0 +1,98 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package norm + +import ( + "strings" + "testing" +) + +func doIterNorm(f Form, s string) []byte { + acc := []byte{} + i := Iter{} + i.InitString(f, s) + for !i.Done() { + acc = append(acc, i.Next()...) + } + return acc +} + +func TestIterNext(t *testing.T) { + runNormTests(t, "IterNext", func(f Form, out []byte, s string) []byte { + return doIterNorm(f, string(append(out, s...))) + }) +} + +type SegmentTest struct { + in string + out []string +} + +var segmentTests = []SegmentTest{ + {"\u1E0A\u0323a", []string{"\x44\u0323\u0307", "a", ""}}, + {rep('a', segSize), append(strings.Split(rep('a', segSize), ""), "")}, + {rep('a', segSize+2), append(strings.Split(rep('a', segSize+2), ""), "")}, + {rep('a', segSize) + "\u0300aa", + append(strings.Split(rep('a', segSize-1), ""), "a\u0300", "a", "a", "")}, + + // U+0f73 is NOT treated as a starter as it is a modifier + {"a" + grave(29) + "\u0f73", []string{"a" + grave(29), cgj + "\u0f73"}}, + {"a\u0f73", []string{"a\u0f73"}}, + + // U+ff9e is treated as a non-starter. + // TODO: should we? Note that this will only affect iteration, as whether + // or not we do so does not affect the normalization output and will either + // way result in consistent iteration output. + {"a" + grave(30) + "\uff9e", []string{"a" + grave(30), cgj + "\uff9e"}}, + {"a\uff9e", []string{"a\uff9e"}}, +} + +var segmentTestsK = []SegmentTest{ + {"\u3332", []string{"\u30D5", "\u30A1", "\u30E9", "\u30C3", "\u30C8\u3099", ""}}, + // last segment of multi-segment decomposition needs normalization + {"\u3332\u093C", []string{"\u30D5", "\u30A1", "\u30E9", "\u30C3", "\u30C8\u093C\u3099", ""}}, + {"\u320E", []string{"\x28", "\uAC00", "\x29"}}, + + // last segment should be copied to start of buffer. + {"\ufdfa", []string{"\u0635", "\u0644", "\u0649", " ", "\u0627", "\u0644", "\u0644", "\u0647", " ", "\u0639", "\u0644", "\u064a", "\u0647", " ", "\u0648", "\u0633", "\u0644", "\u0645", ""}}, + {"\ufdfa" + grave(30), []string{"\u0635", "\u0644", "\u0649", " ", "\u0627", "\u0644", "\u0644", "\u0647", " ", "\u0639", "\u0644", "\u064a", "\u0647", " ", "\u0648", "\u0633", "\u0644", "\u0645" + grave(30), ""}}, + {"\uFDFA" + grave(64), []string{"\u0635", "\u0644", "\u0649", " ", "\u0627", "\u0644", "\u0644", "\u0647", " ", "\u0639", "\u0644", "\u064a", "\u0647", " ", "\u0648", "\u0633", "\u0644", "\u0645" + grave(30), cgj + grave(30), cgj + grave(4), ""}}, + + // Hangul and Jamo are grouped togeter. + {"\uAC00", []string{"\u1100\u1161", ""}}, + {"\uAC01", []string{"\u1100\u1161\u11A8", ""}}, + {"\u1100\u1161", []string{"\u1100\u1161", ""}}, +} + +// Note that, by design, segmentation is equal for composing and decomposing forms. +func TestIterSegmentation(t *testing.T) { + segmentTest(t, "SegmentTestD", NFD, segmentTests) + segmentTest(t, "SegmentTestC", NFC, segmentTests) + segmentTest(t, "SegmentTestKD", NFKD, segmentTestsK) + segmentTest(t, "SegmentTestKC", NFKC, segmentTestsK) +} + +func segmentTest(t *testing.T, name string, f Form, tests []SegmentTest) { + iter := Iter{} + for i, tt := range tests { + iter.InitString(f, tt.in) + for j, seg := range tt.out { + if seg == "" { + if !iter.Done() { + res := string(iter.Next()) + t.Errorf(`%s:%d:%d: expected Done()==true, found segment %+q`, name, i, j, res) + } + continue + } + if iter.Done() { + t.Errorf("%s:%d:%d: Done()==true, want false", name, i, j) + } + seg = f.String(seg) + if res := string(iter.Next()); res != seg { + t.Errorf(`%s:%d:%d" segment was %+q (%d); want %+q (%d)`, name, i, j, pc(res), len(res), pc(seg), len(seg)) + } + } + } +} diff --git a/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/maketables.go b/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/maketables.go new file mode 100644 index 000000000..cd40c9d46 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/maketables.go @@ -0,0 +1,1143 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build ignore + +// Normalization table generator. +// Data read from the web. +// See forminfo.go for a description of the trie values associated with each rune. + +package main + +import ( + "bufio" + "bytes" + "flag" + "fmt" + "io" + "log" + "net/http" + "os" + "regexp" + "sort" + "strconv" + "strings" + "unicode" +) + +func main() { + flag.Parse() + loadUnicodeData() + compactCCC() + loadCompositionExclusions() + completeCharFields(FCanonical) + completeCharFields(FCompatibility) + computeNonStarterCounts() + verifyComputed() + printChars() + if *test { + testDerived() + printTestdata() + } else { + makeTables() + } +} + +var url = flag.String("url", + "http://www.unicode.org/Public/"+unicode.Version+"/ucd/", + "URL of Unicode database directory") +var tablelist = flag.String("tables", + "all", + "comma-separated list of which tables to generate; "+ + "can be 'decomp', 'recomp', 'info' and 'all'") +var test = flag.Bool("test", + false, + "test existing tables against DerivedNormalizationProps and generate test data for regression testing") +var verbose = flag.Bool("verbose", + false, + "write data to stdout as it is parsed") +var localFiles = flag.Bool("local", + false, + "data files have been copied to the current directory; for debugging only") + +var logger = log.New(os.Stderr, "", log.Lshortfile) + +// UnicodeData.txt has form: +// 0037;DIGIT SEVEN;Nd;0;EN;;7;7;7;N;;;;; +// 007A;LATIN SMALL LETTER Z;Ll;0;L;;;;;N;;;005A;;005A +// See http://unicode.org/reports/tr44/ for full explanation +// The fields: +const ( + FCodePoint = iota + FName + FGeneralCategory + FCanonicalCombiningClass + FBidiClass + FDecompMapping + FDecimalValue + FDigitValue + FNumericValue + FBidiMirrored + FUnicode1Name + FISOComment + FSimpleUppercaseMapping + FSimpleLowercaseMapping + FSimpleTitlecaseMapping + NumField + + MaxChar = 0x10FFFF // anything above this shouldn't exist +) + +// Quick Check properties of runes allow us to quickly +// determine whether a rune may occur in a normal form. +// For a given normal form, a rune may be guaranteed to occur +// verbatim (QC=Yes), may or may not combine with another +// rune (QC=Maybe), or may not occur (QC=No). +type QCResult int + +const ( + QCUnknown QCResult = iota + QCYes + QCNo + QCMaybe +) + +func (r QCResult) String() string { + switch r { + case QCYes: + return "Yes" + case QCNo: + return "No" + case QCMaybe: + return "Maybe" + } + return "***UNKNOWN***" +} + +const ( + FCanonical = iota // NFC or NFD + FCompatibility // NFKC or NFKD + FNumberOfFormTypes +) + +const ( + MComposed = iota // NFC or NFKC + MDecomposed // NFD or NFKD + MNumberOfModes +) + +// This contains only the properties we're interested in. +type Char struct { + name string + codePoint rune // if zero, this index is not a valid code point. + ccc uint8 // canonical combining class + origCCC uint8 + excludeInComp bool // from CompositionExclusions.txt + compatDecomp bool // it has a compatibility expansion + + nTrailingNonStarters uint8 + nLeadingNonStarters uint8 // must be equal to trailing if non-zero + + forms [FNumberOfFormTypes]FormInfo // For FCanonical and FCompatibility + + state State +} + +var chars = make([]Char, MaxChar+1) +var cccMap = make(map[uint8]uint8) + +func (c Char) String() string { + buf := new(bytes.Buffer) + + fmt.Fprintf(buf, "%U [%s]:\n", c.codePoint, c.name) + fmt.Fprintf(buf, " ccc: %v\n", c.ccc) + fmt.Fprintf(buf, " excludeInComp: %v\n", c.excludeInComp) + fmt.Fprintf(buf, " compatDecomp: %v\n", c.compatDecomp) + fmt.Fprintf(buf, " state: %v\n", c.state) + fmt.Fprintf(buf, " NFC:\n") + fmt.Fprint(buf, c.forms[FCanonical]) + fmt.Fprintf(buf, " NFKC:\n") + fmt.Fprint(buf, c.forms[FCompatibility]) + + return buf.String() +} + +// In UnicodeData.txt, some ranges are marked like this: +// 3400;;Lo;0;L;;;;;N;;;;; +// 4DB5;;Lo;0;L;;;;;N;;;;; +// parseCharacter keeps a state variable indicating the weirdness. +type State int + +const ( + SNormal State = iota // known to be zero for the type + SFirst + SLast + SMissing +) + +var lastChar = rune('\u0000') + +func (c Char) isValid() bool { + return c.codePoint != 0 && c.state != SMissing +} + +type FormInfo struct { + quickCheck [MNumberOfModes]QCResult // index: MComposed or MDecomposed + verified [MNumberOfModes]bool // index: MComposed or MDecomposed + + combinesForward bool // May combine with rune on the right + combinesBackward bool // May combine with rune on the left + isOneWay bool // Never appears in result + inDecomp bool // Some decompositions result in this char. + decomp Decomposition + expandedDecomp Decomposition +} + +func (f FormInfo) String() string { + buf := bytes.NewBuffer(make([]byte, 0)) + + fmt.Fprintf(buf, " quickCheck[C]: %v\n", f.quickCheck[MComposed]) + fmt.Fprintf(buf, " quickCheck[D]: %v\n", f.quickCheck[MDecomposed]) + fmt.Fprintf(buf, " cmbForward: %v\n", f.combinesForward) + fmt.Fprintf(buf, " cmbBackward: %v\n", f.combinesBackward) + fmt.Fprintf(buf, " isOneWay: %v\n", f.isOneWay) + fmt.Fprintf(buf, " inDecomp: %v\n", f.inDecomp) + fmt.Fprintf(buf, " decomposition: %X\n", f.decomp) + fmt.Fprintf(buf, " expandedDecomp: %X\n", f.expandedDecomp) + + return buf.String() +} + +type Decomposition []rune + +func openReader(file string) (input io.ReadCloser) { + if *localFiles { + f, err := os.Open(file) + if err != nil { + logger.Fatal(err) + } + input = f + } else { + path := *url + file + resp, err := http.Get(path) + if err != nil { + logger.Fatal(err) + } + if resp.StatusCode != 200 { + logger.Fatal("bad GET status for "+file, resp.Status) + } + input = resp.Body + } + return +} + +func parseDecomposition(s string, skipfirst bool) (a []rune, e error) { + decomp := strings.Split(s, " ") + if len(decomp) > 0 && skipfirst { + decomp = decomp[1:] + } + for _, d := range decomp { + point, err := strconv.ParseUint(d, 16, 64) + if err != nil { + return a, err + } + a = append(a, rune(point)) + } + return a, nil +} + +func parseCharacter(line string) { + field := strings.Split(line, ";") + if len(field) != NumField { + logger.Fatalf("%5s: %d fields (expected %d)\n", line, len(field), NumField) + } + x, err := strconv.ParseUint(field[FCodePoint], 16, 64) + point := int(x) + if err != nil { + logger.Fatalf("%.5s...: %s", line, err) + } + if point == 0 { + return // not interesting and we use 0 as unset + } + if point > MaxChar { + logger.Fatalf("%5s: Rune %X > MaxChar (%X)", line, point, MaxChar) + return + } + state := SNormal + switch { + case strings.Index(field[FName], ", First>") > 0: + state = SFirst + case strings.Index(field[FName], ", Last>") > 0: + state = SLast + } + firstChar := lastChar + 1 + lastChar = rune(point) + if state != SLast { + firstChar = lastChar + } + x, err = strconv.ParseUint(field[FCanonicalCombiningClass], 10, 64) + if err != nil { + logger.Fatalf("%U: bad ccc field: %s", int(x), err) + } + ccc := uint8(x) + decmap := field[FDecompMapping] + exp, e := parseDecomposition(decmap, false) + isCompat := false + if e != nil { + if len(decmap) > 0 { + exp, e = parseDecomposition(decmap, true) + if e != nil { + logger.Fatalf(`%U: bad decomp |%v|: "%s"`, int(x), decmap, e) + } + isCompat = true + } + } + for i := firstChar; i <= lastChar; i++ { + char := &chars[i] + char.name = field[FName] + char.codePoint = i + char.forms[FCompatibility].decomp = exp + if !isCompat { + char.forms[FCanonical].decomp = exp + } else { + char.compatDecomp = true + } + if len(decmap) > 0 { + char.forms[FCompatibility].decomp = exp + } + char.ccc = ccc + char.state = SMissing + if i == lastChar { + char.state = state + } + } + return +} + +func loadUnicodeData() { + f := openReader("UnicodeData.txt") + defer f.Close() + scanner := bufio.NewScanner(f) + for scanner.Scan() { + parseCharacter(scanner.Text()) + } + if scanner.Err() != nil { + logger.Fatal(scanner.Err()) + } +} + +// compactCCC converts the sparse set of CCC values to a continguous one, +// reducing the number of bits needed from 8 to 6. +func compactCCC() { + m := make(map[uint8]uint8) + for i := range chars { + c := &chars[i] + m[c.ccc] = 0 + } + cccs := []int{} + for v, _ := range m { + cccs = append(cccs, int(v)) + } + sort.Ints(cccs) + for i, c := range cccs { + cccMap[uint8(i)] = uint8(c) + m[uint8(c)] = uint8(i) + } + for i := range chars { + c := &chars[i] + c.origCCC = c.ccc + c.ccc = m[c.ccc] + } + if len(m) >= 1<<6 { + log.Fatalf("too many difference CCC values: %d >= 64", len(m)) + } +} + +var singlePointRe = regexp.MustCompile(`^([0-9A-F]+) *$`) + +// CompositionExclusions.txt has form: +// 0958 # ... +// See http://unicode.org/reports/tr44/ for full explanation +func parseExclusion(line string) int { + comment := strings.Index(line, "#") + if comment >= 0 { + line = line[0:comment] + } + if len(line) == 0 { + return 0 + } + matches := singlePointRe.FindStringSubmatch(line) + if len(matches) != 2 { + logger.Fatalf("%s: %d matches (expected 1)\n", line, len(matches)) + } + point, err := strconv.ParseUint(matches[1], 16, 64) + if err != nil { + logger.Fatalf("%.5s...: %s", line, err) + } + return int(point) +} + +func loadCompositionExclusions() { + f := openReader("CompositionExclusions.txt") + defer f.Close() + scanner := bufio.NewScanner(f) + for scanner.Scan() { + point := parseExclusion(scanner.Text()) + if point == 0 { + continue + } + c := &chars[point] + if c.excludeInComp { + logger.Fatalf("%U: Duplicate entry in exclusions.", c.codePoint) + } + c.excludeInComp = true + } + if scanner.Err() != nil { + log.Fatal(scanner.Err()) + } +} + +// hasCompatDecomp returns true if any of the recursive +// decompositions contains a compatibility expansion. +// In this case, the character may not occur in NFK*. +func hasCompatDecomp(r rune) bool { + c := &chars[r] + if c.compatDecomp { + return true + } + for _, d := range c.forms[FCompatibility].decomp { + if hasCompatDecomp(d) { + return true + } + } + return false +} + +// Hangul related constants. +const ( + HangulBase = 0xAC00 + HangulEnd = 0xD7A4 // hangulBase + Jamo combinations (19 * 21 * 28) + + JamoLBase = 0x1100 + JamoLEnd = 0x1113 + JamoVBase = 0x1161 + JamoVEnd = 0x1176 + JamoTBase = 0x11A8 + JamoTEnd = 0x11C3 + + JamoLVTCount = 19 * 21 * 28 + JamoTCount = 28 +) + +func isHangul(r rune) bool { + return HangulBase <= r && r < HangulEnd +} + +func isHangulWithoutJamoT(r rune) bool { + if !isHangul(r) { + return false + } + r -= HangulBase + return r < JamoLVTCount && r%JamoTCount == 0 +} + +func ccc(r rune) uint8 { + return chars[r].ccc +} + +// Insert a rune in a buffer, ordered by Canonical Combining Class. +func insertOrdered(b Decomposition, r rune) Decomposition { + n := len(b) + b = append(b, 0) + cc := ccc(r) + if cc > 0 { + // Use bubble sort. + for ; n > 0; n-- { + if ccc(b[n-1]) <= cc { + break + } + b[n] = b[n-1] + } + } + b[n] = r + return b +} + +// Recursively decompose. +func decomposeRecursive(form int, r rune, d Decomposition) Decomposition { + dcomp := chars[r].forms[form].decomp + if len(dcomp) == 0 { + return insertOrdered(d, r) + } + for _, c := range dcomp { + d = decomposeRecursive(form, c, d) + } + return d +} + +func completeCharFields(form int) { + // Phase 0: pre-expand decomposition. + for i := range chars { + f := &chars[i].forms[form] + if len(f.decomp) == 0 { + continue + } + exp := make(Decomposition, 0) + for _, c := range f.decomp { + exp = decomposeRecursive(form, c, exp) + } + f.expandedDecomp = exp + } + + // Phase 1: composition exclusion, mark decomposition. + for i := range chars { + c := &chars[i] + f := &c.forms[form] + + // Marks script-specific exclusions and version restricted. + f.isOneWay = c.excludeInComp + + // Singletons + f.isOneWay = f.isOneWay || len(f.decomp) == 1 + + // Non-starter decompositions + if len(f.decomp) > 1 { + chk := c.ccc != 0 || chars[f.decomp[0]].ccc != 0 + f.isOneWay = f.isOneWay || chk + } + + // Runes that decompose into more than two runes. + f.isOneWay = f.isOneWay || len(f.decomp) > 2 + + if form == FCompatibility { + f.isOneWay = f.isOneWay || hasCompatDecomp(c.codePoint) + } + + for _, r := range f.decomp { + chars[r].forms[form].inDecomp = true + } + } + + // Phase 2: forward and backward combining. + for i := range chars { + c := &chars[i] + f := &c.forms[form] + + if !f.isOneWay && len(f.decomp) == 2 { + f0 := &chars[f.decomp[0]].forms[form] + f1 := &chars[f.decomp[1]].forms[form] + if !f0.isOneWay { + f0.combinesForward = true + } + if !f1.isOneWay { + f1.combinesBackward = true + } + } + if isHangulWithoutJamoT(rune(i)) { + f.combinesForward = true + } + } + + // Phase 3: quick check values. + for i := range chars { + c := &chars[i] + f := &c.forms[form] + + switch { + case len(f.decomp) > 0: + f.quickCheck[MDecomposed] = QCNo + case isHangul(rune(i)): + f.quickCheck[MDecomposed] = QCNo + default: + f.quickCheck[MDecomposed] = QCYes + } + switch { + case f.isOneWay: + f.quickCheck[MComposed] = QCNo + case (i & 0xffff00) == JamoLBase: + f.quickCheck[MComposed] = QCYes + if JamoLBase <= i && i < JamoLEnd { + f.combinesForward = true + } + if JamoVBase <= i && i < JamoVEnd { + f.quickCheck[MComposed] = QCMaybe + f.combinesBackward = true + f.combinesForward = true + } + if JamoTBase <= i && i < JamoTEnd { + f.quickCheck[MComposed] = QCMaybe + f.combinesBackward = true + } + case !f.combinesBackward: + f.quickCheck[MComposed] = QCYes + default: + f.quickCheck[MComposed] = QCMaybe + } + } +} + +func computeNonStarterCounts() { + // Phase 4: leading and trailing non-starter count + for i := range chars { + c := &chars[i] + + runes := []rune{rune(i)} + // We always use FCompatibility so that the CGJ insertion points do not + // change for repeated normalizations with different forms. + if exp := c.forms[FCompatibility].expandedDecomp; len(exp) > 0 { + runes = exp + } + for _, r := range runes { + if chars[r].ccc == 0 { + break + } + c.nLeadingNonStarters++ + } + for i := len(runes) - 1; i >= 0; i-- { + if chars[runes[i]].ccc == 0 { + break + } + c.nTrailingNonStarters++ + } + + // We consider runes that combine backwards to be non-starters for the + // purpose of Stream-Safe Text Processing. + for _, f := range c.forms { + if c.ccc == 0 && f.combinesBackward { + if len(c.forms[FCompatibility].expandedDecomp) > 0 { + log.Fatalf("%U: CCC==0 modifier with an expansion is not supported.", i) + } + c.nTrailingNonStarters = 1 + c.nLeadingNonStarters = 1 + } + } + + if isHangul(rune(i)) { + c.nTrailingNonStarters = 2 + if isHangulWithoutJamoT(rune(i)) { + c.nTrailingNonStarters = 1 + } + } + + if l, t := c.nLeadingNonStarters, c.nTrailingNonStarters; l > 0 && l != t { + log.Fatalf("%U: number of leading and trailing non-starters should be equal (%d vs %d)", i, l, t) + } + if t := c.nTrailingNonStarters; t > 3 { + log.Fatalf("%U: number of trailing non-starters is %d > 3", t) + } + } +} + +func printBytes(b []byte, name string) { + fmt.Printf("// %s: %d bytes\n", name, len(b)) + fmt.Printf("var %s = [...]byte {", name) + for i, c := range b { + switch { + case i%64 == 0: + fmt.Printf("\n// Bytes %x - %x\n", i, i+63) + case i%8 == 0: + fmt.Printf("\n") + } + fmt.Printf("0x%.2X, ", c) + } + fmt.Print("\n}\n\n") +} + +// See forminfo.go for format. +func makeEntry(f *FormInfo, c *Char) uint16 { + e := uint16(0) + if r := c.codePoint; HangulBase <= r && r < HangulEnd { + e |= 0x40 + } + if f.combinesForward { + e |= 0x20 + } + if f.quickCheck[MDecomposed] == QCNo { + e |= 0x4 + } + switch f.quickCheck[MComposed] { + case QCYes: + case QCNo: + e |= 0x10 + case QCMaybe: + e |= 0x18 + default: + log.Fatalf("Illegal quickcheck value %v.", f.quickCheck[MComposed]) + } + e |= uint16(c.nTrailingNonStarters) + return e +} + +// decompSet keeps track of unique decompositions, grouped by whether +// the decomposition is followed by a trailing and/or leading CCC. +type decompSet [7]map[string]bool + +const ( + normalDecomp = iota + firstMulti + firstCCC + endMulti + firstLeadingCCC + firstCCCZeroExcept + firstStarterWithNLead + lastDecomp +) + +var cname = []string{"firstMulti", "firstCCC", "endMulti", "firstLeadingCCC", "firstCCCZeroExcept", "firstStarterWithNLead", "lastDecomp"} + +func makeDecompSet() decompSet { + m := decompSet{} + for i := range m { + m[i] = make(map[string]bool) + } + return m +} +func (m *decompSet) insert(key int, s string) { + m[key][s] = true +} + +func printCharInfoTables() int { + mkstr := func(r rune, f *FormInfo) (int, string) { + d := f.expandedDecomp + s := string([]rune(d)) + if max := 1 << 6; len(s) >= max { + const msg = "%U: too many bytes in decomposition: %d >= %d" + logger.Fatalf(msg, r, len(s), max) + } + head := uint8(len(s)) + if f.quickCheck[MComposed] != QCYes { + head |= 0x40 + } + if f.combinesForward { + head |= 0x80 + } + s = string([]byte{head}) + s + + lccc := ccc(d[0]) + tccc := ccc(d[len(d)-1]) + cc := ccc(r) + if cc != 0 && lccc == 0 && tccc == 0 { + logger.Fatalf("%U: trailing and leading ccc are 0 for non-zero ccc %d", r, cc) + } + if tccc < lccc && lccc != 0 { + const msg = "%U: lccc (%d) must be <= tcc (%d)" + logger.Fatalf(msg, r, lccc, tccc) + } + index := normalDecomp + nTrail := chars[r].nTrailingNonStarters + if tccc > 0 || lccc > 0 || nTrail > 0 { + tccc <<= 2 + tccc |= nTrail + s += string([]byte{tccc}) + index = endMulti + for _, r := range d[1:] { + if ccc(r) == 0 { + index = firstCCC + } + } + if lccc > 0 { + s += string([]byte{lccc}) + if index == firstCCC { + logger.Fatalf("%U: multi-segment decomposition not supported for decompositions with leading CCC != 0", r) + } + index = firstLeadingCCC + } + if cc != lccc { + if cc != 0 { + logger.Fatalf("%U: for lccc != ccc, expected ccc to be 0; was %d", r, cc) + } + index = firstCCCZeroExcept + } + } else if len(d) > 1 { + index = firstMulti + } + return index, s + } + + decompSet := makeDecompSet() + const nLeadStr = "\x00\x01" // 0-byte length and tccc with nTrail. + decompSet.insert(firstStarterWithNLead, nLeadStr) + + // Store the uniqued decompositions in a byte buffer, + // preceded by their byte length. + for _, c := range chars { + for _, f := range c.forms { + if len(f.expandedDecomp) == 0 { + continue + } + if f.combinesBackward { + logger.Fatalf("%U: combinesBackward and decompose", c.codePoint) + } + index, s := mkstr(c.codePoint, &f) + decompSet.insert(index, s) + } + } + + decompositions := bytes.NewBuffer(make([]byte, 0, 10000)) + size := 0 + positionMap := make(map[string]uint16) + decompositions.WriteString("\000") + fmt.Println("const (") + for i, m := range decompSet { + sa := []string{} + for s := range m { + sa = append(sa, s) + } + sort.Strings(sa) + for _, s := range sa { + p := decompositions.Len() + decompositions.WriteString(s) + positionMap[s] = uint16(p) + } + if cname[i] != "" { + fmt.Printf("%s = 0x%X\n", cname[i], decompositions.Len()) + } + } + fmt.Println("maxDecomp = 0x8000") + fmt.Println(")") + b := decompositions.Bytes() + printBytes(b, "decomps") + size += len(b) + + varnames := []string{"nfc", "nfkc"} + for i := 0; i < FNumberOfFormTypes; i++ { + trie := newNode() + for r, c := range chars { + f := c.forms[i] + d := f.expandedDecomp + if len(d) != 0 { + _, key := mkstr(c.codePoint, &f) + trie.insert(rune(r), positionMap[key]) + if c.ccc != ccc(d[0]) { + // We assume the lead ccc of a decomposition !=0 in this case. + if ccc(d[0]) == 0 { + logger.Fatalf("Expected leading CCC to be non-zero; ccc is %d", c.ccc) + } + } + } else if c.nLeadingNonStarters > 0 && len(f.expandedDecomp) == 0 && c.ccc == 0 && !f.combinesBackward { + // Handle cases where it can't be detected that the nLead should be equal + // to nTrail. + trie.insert(c.codePoint, positionMap[nLeadStr]) + } else if v := makeEntry(&f, &c)<<8 | uint16(c.ccc); v != 0 { + trie.insert(c.codePoint, 0x8000|v) + } + } + size += trie.printTables(varnames[i]) + } + return size +} + +func contains(sa []string, s string) bool { + for _, a := range sa { + if a == s { + return true + } + } + return false +} + +// Extract the version number from the URL. +func version() string { + // From http://www.unicode.org/standard/versions/#Version_Numbering: + // for the later Unicode versions, data files are located in + // versioned directories. + fields := strings.Split(*url, "/") + for _, f := range fields { + if match, _ := regexp.MatchString(`[0-9]\.[0-9]\.[0-9]`, f); match { + return f + } + } + logger.Fatal("unknown version") + return "Unknown" +} + +const fileHeader = `// Generated by running +// maketables --tables=%s --url=%s +// DO NOT EDIT + +package norm + +` + +func makeTables() { + size := 0 + if *tablelist == "" { + return + } + list := strings.Split(*tablelist, ",") + if *tablelist == "all" { + list = []string{"recomp", "info"} + } + fmt.Printf(fileHeader, *tablelist, *url) + + // Compute maximum decomposition size. + max := 0 + for _, c := range chars { + if n := len(string(c.forms[FCompatibility].expandedDecomp)); n > max { + max = n + } + } + + fmt.Println("const (") + fmt.Println("\t// Version is the Unicode edition from which the tables are derived.") + fmt.Printf("\tVersion = %q\n", version()) + fmt.Println() + fmt.Println("\t// MaxTransformChunkSize indicates the maximum number of bytes that Transform") + fmt.Println("\t// may need to write atomically for any Form. Making a destination buffer at") + fmt.Println("\t// least this size ensures that Transform can always make progress and that") + fmt.Println("\t// the user does not need to grow the buffer on an ErrShortDst.") + fmt.Printf("\tMaxTransformChunkSize = %d+maxNonStarters*4\n", len(string(0x034F))+max) + fmt.Println(")\n") + + // Print the CCC remap table. + size += len(cccMap) + fmt.Printf("var ccc = [%d]uint8{", len(cccMap)) + for i := 0; i < len(cccMap); i++ { + if i%8 == 0 { + fmt.Println() + } + fmt.Printf("%3d, ", cccMap[uint8(i)]) + } + fmt.Println("\n}\n") + + if contains(list, "info") { + size += printCharInfoTables() + } + + if contains(list, "recomp") { + // Note that we use 32 bit keys, instead of 64 bit. + // This clips the bits of three entries, but we know + // this won't cause a collision. The compiler will catch + // any changes made to UnicodeData.txt that introduces + // a collision. + // Note that the recomposition map for NFC and NFKC + // are identical. + + // Recomposition map + nrentries := 0 + for _, c := range chars { + f := c.forms[FCanonical] + if !f.isOneWay && len(f.decomp) > 0 { + nrentries++ + } + } + sz := nrentries * 8 + size += sz + fmt.Printf("// recompMap: %d bytes (entries only)\n", sz) + fmt.Println("var recompMap = map[uint32]rune{") + for i, c := range chars { + f := c.forms[FCanonical] + d := f.decomp + if !f.isOneWay && len(d) > 0 { + key := uint32(uint16(d[0]))<<16 + uint32(uint16(d[1])) + fmt.Printf("0x%.8X: 0x%.4X,\n", key, i) + } + } + fmt.Printf("}\n\n") + } + + fmt.Printf("// Total size of tables: %dKB (%d bytes)\n", (size+512)/1024, size) +} + +func printChars() { + if *verbose { + for _, c := range chars { + if !c.isValid() || c.state == SMissing { + continue + } + fmt.Println(c) + } + } +} + +// verifyComputed does various consistency tests. +func verifyComputed() { + for i, c := range chars { + for _, f := range c.forms { + isNo := (f.quickCheck[MDecomposed] == QCNo) + if (len(f.decomp) > 0) != isNo && !isHangul(rune(i)) { + log.Fatalf("%U: NF*D QC must be No if rune decomposes", i) + } + + isMaybe := f.quickCheck[MComposed] == QCMaybe + if f.combinesBackward != isMaybe { + log.Fatalf("%U: NF*C QC must be Maybe if combinesBackward", i) + } + if len(f.decomp) > 0 && f.combinesForward && isMaybe { + log.Fatalf("%U: NF*C QC must be Yes or No if combinesForward and decomposes", i) + } + + if len(f.expandedDecomp) != 0 { + continue + } + if a, b := c.nLeadingNonStarters > 0, (c.ccc > 0 || f.combinesBackward); a != b { + // We accept these two runes to be treated differently (it only affects + // segment breaking in iteration, most likely on inproper use), but + // reconsider if more characters are added. + if i != 0xFF9E && i != 0xFF9F { + log.Fatalf("%U: nLead was %v; want %v", i, a, b) + } + } + } + nfc := c.forms[FCanonical] + nfkc := c.forms[FCompatibility] + if nfc.combinesBackward != nfkc.combinesBackward { + logger.Fatalf("%U: Cannot combine combinesBackward\n", c.codePoint) + } + } +} + +var qcRe = regexp.MustCompile(`([0-9A-F\.]+) *; (NF.*_QC); ([YNM]) #.*`) + +// Use values in DerivedNormalizationProps.txt to compare against the +// values we computed. +// DerivedNormalizationProps.txt has form: +// 00C0..00C5 ; NFD_QC; N # ... +// 0374 ; NFD_QC; N # ... +// See http://unicode.org/reports/tr44/ for full explanation +func testDerived() { + f := openReader("DerivedNormalizationProps.txt") + defer f.Close() + scanner := bufio.NewScanner(f) + for scanner.Scan() { + line := scanner.Text() + qc := qcRe.FindStringSubmatch(line) + if qc == nil { + continue + } + rng := strings.Split(qc[1], "..") + i, err := strconv.ParseUint(rng[0], 16, 64) + if err != nil { + log.Fatal(err) + } + j := i + if len(rng) > 1 { + j, err = strconv.ParseUint(rng[1], 16, 64) + if err != nil { + log.Fatal(err) + } + } + var ftype, mode int + qt := strings.TrimSpace(qc[2]) + switch qt { + case "NFC_QC": + ftype, mode = FCanonical, MComposed + case "NFD_QC": + ftype, mode = FCanonical, MDecomposed + case "NFKC_QC": + ftype, mode = FCompatibility, MComposed + case "NFKD_QC": + ftype, mode = FCompatibility, MDecomposed + default: + log.Fatalf(`Unexpected quick check type "%s"`, qt) + } + var qr QCResult + switch qc[3] { + case "Y": + qr = QCYes + case "N": + qr = QCNo + case "M": + qr = QCMaybe + default: + log.Fatalf(`Unexpected quick check value "%s"`, qc[3]) + } + var lastFailed bool + // Verify current + for ; i <= j; i++ { + c := &chars[int(i)] + c.forms[ftype].verified[mode] = true + curqr := c.forms[ftype].quickCheck[mode] + if curqr != qr { + if !lastFailed { + logger.Printf("%s: %.4X..%.4X -- %s\n", + qt, int(i), int(j), line[0:50]) + } + logger.Printf("%U: FAILED %s (was %v need %v)\n", + int(i), qt, curqr, qr) + lastFailed = true + } + } + } + if scanner.Err() != nil { + logger.Fatal(scanner.Err()) + } + // Any unspecified value must be QCYes. Verify this. + for i, c := range chars { + for j, fd := range c.forms { + for k, qr := range fd.quickCheck { + if !fd.verified[k] && qr != QCYes { + m := "%U: FAIL F:%d M:%d (was %v need Yes) %s\n" + logger.Printf(m, i, j, k, qr, c.name) + } + } + } + } +} + +var testHeader = `// Generated by running +// maketables --test --url=%s +// +build test + +package norm + +const ( + Yes = iota + No + Maybe +) + +type formData struct { + qc uint8 + combinesForward bool + decomposition string +} + +type runeData struct { + r rune + ccc uint8 + nLead uint8 + nTrail uint8 + f [2]formData // 0: canonical; 1: compatibility +} + +func f(qc uint8, cf bool, dec string) [2]formData { + return [2]formData{{qc, cf, dec}, {qc, cf, dec}} +} + +func g(qc, qck uint8, cf, cfk bool, d, dk string) [2]formData { + return [2]formData{{qc, cf, d}, {qck, cfk, dk}} +} + +var testData = []runeData{ +` + +func printTestdata() { + type lastInfo struct { + ccc uint8 + nLead uint8 + nTrail uint8 + f string + } + last := lastInfo{} + fmt.Printf(testHeader, *url) + for r, c := range chars { + f := c.forms[FCanonical] + qc, cf, d := f.quickCheck[MComposed], f.combinesForward, string(f.expandedDecomp) + f = c.forms[FCompatibility] + qck, cfk, dk := f.quickCheck[MComposed], f.combinesForward, string(f.expandedDecomp) + s := "" + if d == dk && qc == qck && cf == cfk { + s = fmt.Sprintf("f(%s, %v, %q)", qc, cf, d) + } else { + s = fmt.Sprintf("g(%s, %s, %v, %v, %q, %q)", qc, qck, cf, cfk, d, dk) + } + current := lastInfo{c.ccc, c.nLeadingNonStarters, c.nTrailingNonStarters, s} + if last != current { + fmt.Printf("\t{0x%x, %d, %d, %d, %s},\n", r, c.origCCC, c.nLeadingNonStarters, c.nTrailingNonStarters, s) + last = current + } + } + fmt.Println("}") +} diff --git a/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/maketesttables.go b/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/maketesttables.go new file mode 100644 index 000000000..6d11ec069 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/maketesttables.go @@ -0,0 +1,45 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build ignore + +// Generate test data for trie code. + +package main + +import ( + "fmt" +) + +func main() { + printTestTables() +} + +// We take the smallest, largest and an arbitrary value for each +// of the UTF-8 sequence lengths. +var testRunes = []rune{ + 0x01, 0x0C, 0x7F, // 1-byte sequences + 0x80, 0x100, 0x7FF, // 2-byte sequences + 0x800, 0x999, 0xFFFF, // 3-byte sequences + 0x10000, 0x10101, 0x10FFFF, // 4-byte sequences + 0x200, 0x201, 0x202, 0x210, 0x215, // five entries in one sparse block +} + +const fileHeader = `// Generated by running +// maketesttables +// DO NOT EDIT + +package norm + +` + +func printTestTables() { + fmt.Print(fileHeader) + fmt.Printf("var testRunes = %#v\n\n", testRunes) + t := newNode() + for i, r := range testRunes { + t.insert(r, uint16(i)) + } + t.printTables("testdata") +} diff --git a/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/norm_test.go b/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/norm_test.go new file mode 100644 index 000000000..12dacfcf3 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/norm_test.go @@ -0,0 +1,14 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package norm_test + +import ( + "testing" +) + +func TestPlaceHolder(t *testing.T) { + // Does nothing, just allows the Makefile to be canonical + // while waiting for the package itself to be written. +} diff --git a/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/normalize.go b/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/normalize.go new file mode 100644 index 000000000..d81728494 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/normalize.go @@ -0,0 +1,524 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package norm contains types and functions for normalizing Unicode strings. +package norm + +import "unicode/utf8" + +// A Form denotes a canonical representation of Unicode code points. +// The Unicode-defined normalization and equivalence forms are: +// +// NFC Unicode Normalization Form C +// NFD Unicode Normalization Form D +// NFKC Unicode Normalization Form KC +// NFKD Unicode Normalization Form KD +// +// For a Form f, this documentation uses the notation f(x) to mean +// the bytes or string x converted to the given form. +// A position n in x is called a boundary if conversion to the form can +// proceed independently on both sides: +// f(x) == append(f(x[0:n]), f(x[n:])...) +// +// References: http://unicode.org/reports/tr15/ and +// http://unicode.org/notes/tn5/. +type Form int + +const ( + NFC Form = iota + NFD + NFKC + NFKD +) + +// Bytes returns f(b). May return b if f(b) = b. +func (f Form) Bytes(b []byte) []byte { + src := inputBytes(b) + ft := formTable[f] + n, ok := ft.quickSpan(src, 0, len(b), true) + if ok { + return b + } + out := make([]byte, n, len(b)) + copy(out, b[0:n]) + rb := reorderBuffer{f: *ft, src: src, nsrc: len(b), out: out, flushF: appendFlush} + return doAppendInner(&rb, n) +} + +// String returns f(s). +func (f Form) String(s string) string { + src := inputString(s) + ft := formTable[f] + n, ok := ft.quickSpan(src, 0, len(s), true) + if ok { + return s + } + out := make([]byte, n, len(s)) + copy(out, s[0:n]) + rb := reorderBuffer{f: *ft, src: src, nsrc: len(s), out: out, flushF: appendFlush} + return string(doAppendInner(&rb, n)) +} + +// IsNormal returns true if b == f(b). +func (f Form) IsNormal(b []byte) bool { + src := inputBytes(b) + ft := formTable[f] + bp, ok := ft.quickSpan(src, 0, len(b), true) + if ok { + return true + } + rb := reorderBuffer{f: *ft, src: src, nsrc: len(b)} + rb.setFlusher(nil, cmpNormalBytes) + for bp < len(b) { + rb.out = b[bp:] + if bp = decomposeSegment(&rb, bp, true); bp < 0 { + return false + } + bp, _ = rb.f.quickSpan(rb.src, bp, len(b), true) + } + return true +} + +func cmpNormalBytes(rb *reorderBuffer) bool { + b := rb.out + for i := 0; i < rb.nrune; i++ { + info := rb.rune[i] + if int(info.size) > len(b) { + return false + } + p := info.pos + pe := p + info.size + for ; p < pe; p++ { + if b[0] != rb.byte[p] { + return false + } + b = b[1:] + } + } + return true +} + +// IsNormalString returns true if s == f(s). +func (f Form) IsNormalString(s string) bool { + src := inputString(s) + ft := formTable[f] + bp, ok := ft.quickSpan(src, 0, len(s), true) + if ok { + return true + } + rb := reorderBuffer{f: *ft, src: src, nsrc: len(s)} + rb.setFlusher(nil, func(rb *reorderBuffer) bool { + for i := 0; i < rb.nrune; i++ { + info := rb.rune[i] + if bp+int(info.size) > len(s) { + return false + } + p := info.pos + pe := p + info.size + for ; p < pe; p++ { + if s[bp] != rb.byte[p] { + return false + } + bp++ + } + } + return true + }) + for bp < len(s) { + if bp = decomposeSegment(&rb, bp, true); bp < 0 { + return false + } + bp, _ = rb.f.quickSpan(rb.src, bp, len(s), true) + } + return true +} + +// patchTail fixes a case where a rune may be incorrectly normalized +// if it is followed by illegal continuation bytes. It returns the +// patched buffer and whether the decomposition is still in progress. +func patchTail(rb *reorderBuffer) bool { + info, p := lastRuneStart(&rb.f, rb.out) + if p == -1 || info.size == 0 { + return true + } + end := p + int(info.size) + extra := len(rb.out) - end + if extra > 0 { + // Potentially allocating memory. However, this only + // happens with ill-formed UTF-8. + x := make([]byte, 0) + x = append(x, rb.out[len(rb.out)-extra:]...) + rb.out = rb.out[:end] + decomposeToLastBoundary(rb) + rb.doFlush() + rb.out = append(rb.out, x...) + return false + } + buf := rb.out[p:] + rb.out = rb.out[:p] + decomposeToLastBoundary(rb) + if s := rb.ss.next(info); s == ssStarter { + rb.doFlush() + rb.ss.first(info) + } else if s == ssOverflow { + rb.doFlush() + rb.insertCGJ() + rb.ss = 0 + } + rb.insertUnsafe(inputBytes(buf), 0, info) + return true +} + +func appendQuick(rb *reorderBuffer, i int) int { + if rb.nsrc == i { + return i + } + end, _ := rb.f.quickSpan(rb.src, i, rb.nsrc, true) + rb.out = rb.src.appendSlice(rb.out, i, end) + return end +} + +// Append returns f(append(out, b...)). +// The buffer out must be nil, empty, or equal to f(out). +func (f Form) Append(out []byte, src ...byte) []byte { + return f.doAppend(out, inputBytes(src), len(src)) +} + +func (f Form) doAppend(out []byte, src input, n int) []byte { + if n == 0 { + return out + } + ft := formTable[f] + // Attempt to do a quickSpan first so we can avoid initializing the reorderBuffer. + if len(out) == 0 { + p, _ := ft.quickSpan(src, 0, n, true) + out = src.appendSlice(out, 0, p) + if p == n { + return out + } + rb := reorderBuffer{f: *ft, src: src, nsrc: n, out: out, flushF: appendFlush} + return doAppendInner(&rb, p) + } + rb := reorderBuffer{f: *ft, src: src, nsrc: n} + return doAppend(&rb, out, 0) +} + +func doAppend(rb *reorderBuffer, out []byte, p int) []byte { + rb.setFlusher(out, appendFlush) + src, n := rb.src, rb.nsrc + doMerge := len(out) > 0 + if q := src.skipContinuationBytes(p); q > p { + // Move leading non-starters to destination. + rb.out = src.appendSlice(rb.out, p, q) + p = q + doMerge = patchTail(rb) + } + fd := &rb.f + if doMerge { + var info Properties + if p < n { + info = fd.info(src, p) + if !info.BoundaryBefore() || info.nLeadingNonStarters() > 0 { + if p == 0 { + decomposeToLastBoundary(rb) + } + p = decomposeSegment(rb, p, true) + } + } + if info.size == 0 { + rb.doFlush() + // Append incomplete UTF-8 encoding. + return src.appendSlice(rb.out, p, n) + } + if rb.nrune > 0 { + return doAppendInner(rb, p) + } + } + p = appendQuick(rb, p) + return doAppendInner(rb, p) +} + +func doAppendInner(rb *reorderBuffer, p int) []byte { + for n := rb.nsrc; p < n; { + p = decomposeSegment(rb, p, true) + p = appendQuick(rb, p) + } + return rb.out +} + +// AppendString returns f(append(out, []byte(s))). +// The buffer out must be nil, empty, or equal to f(out). +func (f Form) AppendString(out []byte, src string) []byte { + return f.doAppend(out, inputString(src), len(src)) +} + +// QuickSpan returns a boundary n such that b[0:n] == f(b[0:n]). +// It is not guaranteed to return the largest such n. +func (f Form) QuickSpan(b []byte) int { + n, _ := formTable[f].quickSpan(inputBytes(b), 0, len(b), true) + return n +} + +// quickSpan returns a boundary n such that src[0:n] == f(src[0:n]) and +// whether any non-normalized parts were found. If atEOF is false, n will +// not point past the last segment if this segment might be become +// non-normalized by appending other runes. +func (f *formInfo) quickSpan(src input, i, end int, atEOF bool) (n int, ok bool) { + var lastCC uint8 + ss := streamSafe(0) + lastSegStart := i + for n = end; i < n; { + if j := src.skipASCII(i, n); i != j { + i = j + lastSegStart = i - 1 + lastCC = 0 + ss = 0 + continue + } + info := f.info(src, i) + if info.size == 0 { + if atEOF { + // include incomplete runes + return n, true + } + return lastSegStart, true + } + // This block needs to be before the next, because it is possible to + // have an overflow for runes that are starters (e.g. with U+FF9E). + switch ss.next(info) { + case ssStarter: + ss.first(info) + lastSegStart = i + case ssOverflow: + return lastSegStart, false + case ssSuccess: + if lastCC > info.ccc { + return lastSegStart, false + } + } + if f.composing { + if !info.isYesC() { + break + } + } else { + if !info.isYesD() { + break + } + } + lastCC = info.ccc + i += int(info.size) + } + if i == n { + if !atEOF { + n = lastSegStart + } + return n, true + } + return lastSegStart, false +} + +// QuickSpanString returns a boundary n such that b[0:n] == f(s[0:n]). +// It is not guaranteed to return the largest such n. +func (f Form) QuickSpanString(s string) int { + n, _ := formTable[f].quickSpan(inputString(s), 0, len(s), true) + return n +} + +// FirstBoundary returns the position i of the first boundary in b +// or -1 if b contains no boundary. +func (f Form) FirstBoundary(b []byte) int { + return f.firstBoundary(inputBytes(b), len(b)) +} + +func (f Form) firstBoundary(src input, nsrc int) int { + i := src.skipContinuationBytes(0) + if i >= nsrc { + return -1 + } + fd := formTable[f] + ss := streamSafe(0) + // We should call ss.first here, but we can't as the first rune is + // skipped already. This means FirstBoundary can't really determine + // CGJ insertion points correctly. Luckily it doesn't have to. + // TODO: consider adding NextBoundary + for { + info := fd.info(src, i) + if info.size == 0 { + return -1 + } + if s := ss.next(info); s != ssSuccess { + return i + } + i += int(info.size) + if i >= nsrc { + if !info.BoundaryAfter() && !ss.isMax() { + return -1 + } + return nsrc + } + } +} + +// FirstBoundaryInString returns the position i of the first boundary in s +// or -1 if s contains no boundary. +func (f Form) FirstBoundaryInString(s string) int { + return f.firstBoundary(inputString(s), len(s)) +} + +// LastBoundary returns the position i of the last boundary in b +// or -1 if b contains no boundary. +func (f Form) LastBoundary(b []byte) int { + return lastBoundary(formTable[f], b) +} + +func lastBoundary(fd *formInfo, b []byte) int { + i := len(b) + info, p := lastRuneStart(fd, b) + if p == -1 { + return -1 + } + if info.size == 0 { // ends with incomplete rune + if p == 0 { // starts with incomplete rune + return -1 + } + i = p + info, p = lastRuneStart(fd, b[:i]) + if p == -1 { // incomplete UTF-8 encoding or non-starter bytes without a starter + return i + } + } + if p+int(info.size) != i { // trailing non-starter bytes: illegal UTF-8 + return i + } + if info.BoundaryAfter() { + return i + } + ss := streamSafe(0) + v := ss.backwards(info) + for i = p; i >= 0 && v != ssStarter; i = p { + info, p = lastRuneStart(fd, b[:i]) + if v = ss.backwards(info); v == ssOverflow { + break + } + if p+int(info.size) != i { + if p == -1 { // no boundary found + return -1 + } + return i // boundary after an illegal UTF-8 encoding + } + } + return i +} + +// decomposeSegment scans the first segment in src into rb. It inserts 0x034f +// (Grapheme Joiner) when it encounters a sequence of more than 30 non-starters +// and returns the number of bytes consumed from src or iShortDst or iShortSrc. +func decomposeSegment(rb *reorderBuffer, sp int, atEOF bool) int { + // Force one character to be consumed. + info := rb.f.info(rb.src, sp) + if info.size == 0 { + return 0 + } + if rb.nrune > 0 { + if s := rb.ss.next(info); s == ssStarter { + goto end + } else if s == ssOverflow { + rb.insertCGJ() + goto end + } + } else { + rb.ss.first(info) + } + if err := rb.insertFlush(rb.src, sp, info); err != iSuccess { + return int(err) + } + for { + sp += int(info.size) + if sp >= rb.nsrc { + if !atEOF && !info.BoundaryAfter() { + return int(iShortSrc) + } + break + } + info = rb.f.info(rb.src, sp) + if info.size == 0 { + if !atEOF { + return int(iShortSrc) + } + break + } + if s := rb.ss.next(info); s == ssStarter { + break + } else if s == ssOverflow { + rb.insertCGJ() + break + } + if err := rb.insertFlush(rb.src, sp, info); err != iSuccess { + return int(err) + } + } +end: + if !rb.doFlush() { + return int(iShortDst) + } + return sp +} + +// lastRuneStart returns the runeInfo and position of the last +// rune in buf or the zero runeInfo and -1 if no rune was found. +func lastRuneStart(fd *formInfo, buf []byte) (Properties, int) { + p := len(buf) - 1 + for ; p >= 0 && !utf8.RuneStart(buf[p]); p-- { + } + if p < 0 { + return Properties{}, -1 + } + return fd.info(inputBytes(buf), p), p +} + +// decomposeToLastBoundary finds an open segment at the end of the buffer +// and scans it into rb. Returns the buffer minus the last segment. +func decomposeToLastBoundary(rb *reorderBuffer) { + fd := &rb.f + info, i := lastRuneStart(fd, rb.out) + if int(info.size) != len(rb.out)-i { + // illegal trailing continuation bytes + return + } + if info.BoundaryAfter() { + return + } + var add [maxNonStarters + 1]Properties // stores runeInfo in reverse order + padd := 0 + ss := streamSafe(0) + p := len(rb.out) + for { + add[padd] = info + v := ss.backwards(info) + if v == ssOverflow { + // Note that if we have an overflow, it the string we are appending to + // is not correctly normalized. In this case the behavior is undefined. + break + } + padd++ + p -= int(info.size) + if v == ssStarter || p < 0 { + break + } + info, i = lastRuneStart(fd, rb.out[:p]) + if int(info.size) != p-i { + break + } + } + rb.ss = ss + // Copy bytes for insertion as we may need to overwrite rb.out. + var buf [maxBufferSize * utf8.UTFMax]byte + cp := buf[:copy(buf[:], rb.out[p:])] + rb.out = rb.out[:p] + for padd--; padd >= 0; padd-- { + info = add[padd] + rb.insertUnsafe(inputBytes(cp), 0, info) + cp = cp[info.size:] + } +} diff --git a/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/normalize_test.go b/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/normalize_test.go new file mode 100644 index 000000000..643d11edf --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/normalize_test.go @@ -0,0 +1,1086 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package norm + +import ( + "bytes" + "flag" + "fmt" + "io" + "log" + "strings" + "testing" + "unicode/utf8" +) + +var ( + testn = flag.Int("testn", -1, "specific test number to run or -1 for all") +) + +// pc replaces any rune r that is repeated n times, for n > 1, with r{n}. +func pc(s string) []byte { + b := bytes.NewBuffer(make([]byte, 0, len(s))) + for i := 0; i < len(s); { + r, sz := utf8.DecodeRuneInString(s[i:]) + n := 0 + if sz == 1 { + // Special-case one-byte case to handle repetition for invalid UTF-8. + for c := s[i]; i+n < len(s) && s[i+n] == c; n++ { + } + } else { + for _, r2 := range s[i:] { + if r2 != r { + break + } + n++ + } + } + b.WriteString(s[i : i+sz]) + if n > 1 { + fmt.Fprintf(b, "{%d}", n) + } + i += sz * n + } + return b.Bytes() +} + +// pidx finds the index from which two strings start to differ, plus context. +// It returns the index and ellipsis if the index is greater than 0. +func pidx(a, b string) (i int, prefix string) { + for ; i < len(a) && i < len(b) && a[i] == b[i]; i++ { + } + if i < 8 { + return 0, "" + } + i -= 3 // ensure taking at least one full rune before the difference. + for k := i - 7; i > k && !utf8.RuneStart(a[i]); i-- { + } + return i, "..." +} + +type PositionTest struct { + input string + pos int + buffer string // expected contents of reorderBuffer, if applicable +} + +type positionFunc func(rb *reorderBuffer, s string) (int, []byte) + +func runPosTests(t *testing.T, name string, f Form, fn positionFunc, tests []PositionTest) { + rb := reorderBuffer{} + rb.init(f, nil) + for i, test := range tests { + rb.reset() + rb.src = inputString(test.input) + rb.nsrc = len(test.input) + pos, out := fn(&rb, test.input) + if pos != test.pos { + t.Errorf("%s:%d: position is %d; want %d", name, i, pos, test.pos) + } + if outs := string(out); outs != test.buffer { + k, pfx := pidx(outs, test.buffer) + t.Errorf("%s:%d: buffer \nwas %s%+q; \nwant %s%+q", name, i, pfx, pc(outs[k:]), pfx, pc(test.buffer[k:])) + } + } +} + +func grave(n int) string { + return rep(0x0300, n) +} + +func rep(r rune, n int) string { + return strings.Repeat(string(r), n) +} + +const segSize = maxByteBufferSize + +var cgj = GraphemeJoiner + +var decomposeSegmentTests = []PositionTest{ + // illegal runes + {"\xC0", 0, ""}, + {"\u00E0\x80", 2, "\u0061\u0300"}, + // starter + {"a", 1, "a"}, + {"ab", 1, "a"}, + // starter + composing + {"a\u0300", 3, "a\u0300"}, + {"a\u0300b", 3, "a\u0300"}, + // with decomposition + {"\u00C0", 2, "A\u0300"}, + {"\u00C0b", 2, "A\u0300"}, + // long + {grave(31), 60, grave(30) + cgj}, + {grave(30), 60, grave(30)}, + {grave(30) + "\uff9e", 60, grave(30) + cgj}, + // ends with incomplete UTF-8 encoding + {"\xCC", 0, ""}, + {"\u0300\xCC", 2, "\u0300"}, +} + +func decomposeSegmentF(rb *reorderBuffer, s string) (int, []byte) { + rb.initString(NFD, s) + rb.setFlusher(nil, appendFlush) + p := decomposeSegment(rb, 0, true) + return p, rb.out +} + +func TestDecomposeSegment(t *testing.T) { + runPosTests(t, "TestDecomposeSegment", NFC, decomposeSegmentF, decomposeSegmentTests) +} + +var firstBoundaryTests = []PositionTest{ + // no boundary + {"", -1, ""}, + {"\u0300", -1, ""}, + {"\x80\x80", -1, ""}, + // illegal runes + {"\xff", 0, ""}, + {"\u0300\xff", 2, ""}, + {"\u0300\xc0\x80\x80", 2, ""}, + // boundaries + {"a", 0, ""}, + {"\u0300a", 2, ""}, + // Hangul + {"\u1103\u1161", 0, ""}, + {"\u110B\u1173\u11B7", 0, ""}, + {"\u1161\u110B\u1173\u11B7", 3, ""}, + {"\u1173\u11B7\u1103\u1161", 6, ""}, + // too many combining characters. + {grave(maxNonStarters - 1), -1, ""}, + {grave(maxNonStarters), 60, ""}, + {grave(maxNonStarters + 1), 60, ""}, +} + +func firstBoundaryF(rb *reorderBuffer, s string) (int, []byte) { + return rb.f.form.FirstBoundary([]byte(s)), nil +} + +func firstBoundaryStringF(rb *reorderBuffer, s string) (int, []byte) { + return rb.f.form.FirstBoundaryInString(s), nil +} + +func TestFirstBoundary(t *testing.T) { + runPosTests(t, "TestFirstBoundary", NFC, firstBoundaryF, firstBoundaryTests) + runPosTests(t, "TestFirstBoundaryInString", NFC, firstBoundaryStringF, firstBoundaryTests) +} + +var decomposeToLastTests = []PositionTest{ + // ends with inert character + {"Hello!", 6, ""}, + {"\u0632", 2, ""}, + {"a\u0301\u0635", 5, ""}, + // ends with non-inert starter + {"a", 0, "a"}, + {"a\u0301a", 3, "a"}, + {"a\u0301\u03B9", 3, "\u03B9"}, + {"a\u0327", 0, "a\u0327"}, + // illegal runes + {"\xFF", 1, ""}, + {"aa\xFF", 3, ""}, + {"\xC0\x80\x80", 3, ""}, + {"\xCC\x80\x80", 3, ""}, + // ends with incomplete UTF-8 encoding + {"a\xCC", 2, ""}, + // ends with combining characters + {"\u0300\u0301", 0, "\u0300\u0301"}, + {"a\u0300\u0301", 0, "a\u0300\u0301"}, + {"a\u0301\u0308", 0, "a\u0301\u0308"}, + {"a\u0308\u0301", 0, "a\u0308\u0301"}, + {"aaaa\u0300\u0301", 3, "a\u0300\u0301"}, + {"\u0300a\u0300\u0301", 2, "a\u0300\u0301"}, + {"\u00C0", 0, "A\u0300"}, + {"a\u00C0", 1, "A\u0300"}, + // decomposing + {"a\u0300\u00E0", 3, "a\u0300"}, + // multisegment decompositions (flushes leading segments) + {"a\u0300\uFDC0", 7, "\u064A"}, + {"\uFDC0" + grave(29), 4, "\u064A" + grave(29)}, + {"\uFDC0" + grave(30), 4, "\u064A" + grave(30)}, + {"\uFDC0" + grave(31), 5, grave(30)}, + {"\uFDFA" + grave(14), 31, "\u0645" + grave(14)}, + // Overflow + {"\u00E0" + grave(29), 0, "a" + grave(30)}, + {"\u00E0" + grave(30), 2, grave(30)}, + // Hangul + {"a\u1103", 1, "\u1103"}, + {"a\u110B", 1, "\u110B"}, + {"a\u110B\u1173", 1, "\u110B\u1173"}, + // See comment in composition.go:compBoundaryAfter. + {"a\u110B\u1173\u11B7", 1, "\u110B\u1173\u11B7"}, + {"a\uC73C", 1, "\u110B\u1173"}, + {"다음", 3, "\u110B\u1173\u11B7"}, + {"다", 0, "\u1103\u1161"}, + {"\u1103\u1161\u110B\u1173\u11B7", 6, "\u110B\u1173\u11B7"}, + {"\u110B\u1173\u11B7\u1103\u1161", 9, "\u1103\u1161"}, + {"다음음", 6, "\u110B\u1173\u11B7"}, + {"음다다", 6, "\u1103\u1161"}, + // maximized buffer + {"a" + grave(30), 0, "a" + grave(30)}, + // Buffer overflow + {"a" + grave(31), 3, grave(30)}, + // weird UTF-8 + {"a\u0300\u11B7", 0, "a\u0300\u11B7"}, +} + +func decomposeToLast(rb *reorderBuffer, s string) (int, []byte) { + rb.setFlusher([]byte(s), appendFlush) + decomposeToLastBoundary(rb) + buf := rb.flush(nil) + return len(rb.out), buf +} + +func TestDecomposeToLastBoundary(t *testing.T) { + runPosTests(t, "TestDecomposeToLastBoundary", NFKC, decomposeToLast, decomposeToLastTests) +} + +var lastBoundaryTests = []PositionTest{ + // ends with inert character + {"Hello!", 6, ""}, + {"\u0632", 2, ""}, + // ends with non-inert starter + {"a", 0, ""}, + // illegal runes + {"\xff", 1, ""}, + {"aa\xff", 3, ""}, + {"a\xff\u0300", 1, ""}, + {"\xc0\x80\x80", 3, ""}, + {"\xc0\x80\x80\u0300", 3, ""}, + // ends with incomplete UTF-8 encoding + {"\xCC", -1, ""}, + {"\xE0\x80", -1, ""}, + {"\xF0\x80\x80", -1, ""}, + {"a\xCC", 0, ""}, + {"\x80\xCC", 1, ""}, + {"\xCC\xCC", 1, ""}, + // ends with combining characters + {"a\u0300\u0301", 0, ""}, + {"aaaa\u0300\u0301", 3, ""}, + {"\u0300a\u0300\u0301", 2, ""}, + {"\u00C0", 0, ""}, + {"a\u00C0", 1, ""}, + // decomposition may recombine + {"\u0226", 0, ""}, + // no boundary + {"", -1, ""}, + {"\u0300\u0301", -1, ""}, + {"\u0300", -1, ""}, + {"\x80\x80", -1, ""}, + {"\x80\x80\u0301", -1, ""}, + // Hangul + {"다음", 3, ""}, + {"다", 0, ""}, + {"\u1103\u1161\u110B\u1173\u11B7", 6, ""}, + {"\u110B\u1173\u11B7\u1103\u1161", 9, ""}, + // too many combining characters. + {grave(maxNonStarters - 1), -1, ""}, + // May still be preceded with a non-starter. + {grave(maxNonStarters), -1, ""}, + // May still need to insert a cgj after the last combiner. + {grave(maxNonStarters + 1), 2, ""}, + {grave(maxNonStarters + 2), 4, ""}, + + {"a" + grave(maxNonStarters-1), 0, ""}, + {"a" + grave(maxNonStarters), 0, ""}, + // May still need to insert a cgj after the last combiner. + {"a" + grave(maxNonStarters+1), 3, ""}, + {"a" + grave(maxNonStarters+2), 5, ""}, +} + +func lastBoundaryF(rb *reorderBuffer, s string) (int, []byte) { + return rb.f.form.LastBoundary([]byte(s)), nil +} + +func TestLastBoundary(t *testing.T) { + runPosTests(t, "TestLastBoundary", NFC, lastBoundaryF, lastBoundaryTests) +} + +var quickSpanTests = []PositionTest{ + {"", 0, ""}, + // starters + {"a", 1, ""}, + {"abc", 3, ""}, + {"\u043Eb", 3, ""}, + // incomplete last rune. + {"\xCC", 1, ""}, + {"a\xCC", 2, ""}, + // incorrectly ordered combining characters + {"\u0300\u0316", 0, ""}, + {"\u0300\u0316cd", 0, ""}, + // have a maximum number of combining characters. + {rep(0x035D, 30) + "\u035B", 0, ""}, + {"a" + rep(0x035D, 30) + "\u035B", 0, ""}, + {"Ɵ" + rep(0x035D, 30) + "\u035B", 0, ""}, + {"aa" + rep(0x035D, 30) + "\u035B", 1, ""}, + {rep(0x035D, 30) + cgj + "\u035B", 64, ""}, + {"a" + rep(0x035D, 30) + cgj + "\u035B", 65, ""}, + {"Ɵ" + rep(0x035D, 30) + cgj + "\u035B", 66, ""}, + {"aa" + rep(0x035D, 30) + cgj + "\u035B", 66, ""}, +} + +var quickSpanNFDTests = []PositionTest{ + // needs decomposing + {"\u00C0", 0, ""}, + {"abc\u00C0", 3, ""}, + // correctly ordered combining characters + {"\u0300", 2, ""}, + {"ab\u0300", 4, ""}, + {"ab\u0300cd", 6, ""}, + {"\u0300cd", 4, ""}, + {"\u0316\u0300", 4, ""}, + {"ab\u0316\u0300", 6, ""}, + {"ab\u0316\u0300cd", 8, ""}, + {"ab\u0316\u0300\u00C0", 6, ""}, + {"\u0316\u0300cd", 6, ""}, + {"\u043E\u0308b", 5, ""}, + // incorrectly ordered combining characters + {"ab\u0300\u0316", 1, ""}, // TODO: we could skip 'b' as well. + {"ab\u0300\u0316cd", 1, ""}, + // Hangul + {"같은", 0, ""}, +} + +var quickSpanNFCTests = []PositionTest{ + // okay composed + {"\u00C0", 2, ""}, + {"abc\u00C0", 5, ""}, + // correctly ordered combining characters + {"ab\u0300", 1, ""}, + {"ab\u0300cd", 1, ""}, + {"ab\u0316\u0300", 1, ""}, + {"ab\u0316\u0300cd", 1, ""}, + {"\u00C0\u035D", 4, ""}, + // we do not special case leading combining characters + {"\u0300cd", 0, ""}, + {"\u0300", 0, ""}, + {"\u0316\u0300", 0, ""}, + {"\u0316\u0300cd", 0, ""}, + // incorrectly ordered combining characters + {"ab\u0300\u0316", 1, ""}, + {"ab\u0300\u0316cd", 1, ""}, + // Hangul + {"같은", 6, ""}, + // We return the start of the violating segment in case of overflow. + {grave(30) + "\uff9e", 0, ""}, + {grave(30), 0, ""}, +} + +func doQuickSpan(rb *reorderBuffer, s string) (int, []byte) { + return rb.f.form.QuickSpan([]byte(s)), nil +} + +func doQuickSpanString(rb *reorderBuffer, s string) (int, []byte) { + return rb.f.form.QuickSpanString(s), nil +} + +func TestQuickSpan(t *testing.T) { + runPosTests(t, "TestQuickSpanNFD1", NFD, doQuickSpan, quickSpanTests) + runPosTests(t, "TestQuickSpanNFD2", NFD, doQuickSpan, quickSpanNFDTests) + runPosTests(t, "TestQuickSpanNFC1", NFC, doQuickSpan, quickSpanTests) + runPosTests(t, "TestQuickSpanNFC2", NFC, doQuickSpan, quickSpanNFCTests) + + runPosTests(t, "TestQuickSpanStringNFD1", NFD, doQuickSpanString, quickSpanTests) + runPosTests(t, "TestQuickSpanStringNFD2", NFD, doQuickSpanString, quickSpanNFDTests) + runPosTests(t, "TestQuickSpanStringNFC1", NFC, doQuickSpanString, quickSpanTests) + runPosTests(t, "TestQuickSpanStringNFC2", NFC, doQuickSpanString, quickSpanNFCTests) +} + +var isNormalTests = []PositionTest{ + {"", 1, ""}, + // illegal runes + {"\xff", 1, ""}, + // starters + {"a", 1, ""}, + {"abc", 1, ""}, + {"\u043Eb", 1, ""}, + // incorrectly ordered combining characters + {"\u0300\u0316", 0, ""}, + {"ab\u0300\u0316", 0, ""}, + {"ab\u0300\u0316cd", 0, ""}, + {"\u0300\u0316cd", 0, ""}, +} +var isNormalNFDTests = []PositionTest{ + // needs decomposing + {"\u00C0", 0, ""}, + {"abc\u00C0", 0, ""}, + // correctly ordered combining characters + {"\u0300", 1, ""}, + {"ab\u0300", 1, ""}, + {"ab\u0300cd", 1, ""}, + {"\u0300cd", 1, ""}, + {"\u0316\u0300", 1, ""}, + {"ab\u0316\u0300", 1, ""}, + {"ab\u0316\u0300cd", 1, ""}, + {"\u0316\u0300cd", 1, ""}, + {"\u043E\u0308b", 1, ""}, + // Hangul + {"같은", 0, ""}, +} +var isNormalNFCTests = []PositionTest{ + // okay composed + {"\u00C0", 1, ""}, + {"abc\u00C0", 1, ""}, + // need reordering + {"a\u0300", 0, ""}, + {"a\u0300cd", 0, ""}, + {"a\u0316\u0300", 0, ""}, + {"a\u0316\u0300cd", 0, ""}, + // correctly ordered combining characters + {"ab\u0300", 1, ""}, + {"ab\u0300cd", 1, ""}, + {"ab\u0316\u0300", 1, ""}, + {"ab\u0316\u0300cd", 1, ""}, + {"\u00C0\u035D", 1, ""}, + {"\u0300", 1, ""}, + {"\u0316\u0300cd", 1, ""}, + // Hangul + {"같은", 1, ""}, +} + +var isNormalNFKXTests = []PositionTest{ + // Special case. + {"\u00BC", 0, ""}, +} + +func isNormalF(rb *reorderBuffer, s string) (int, []byte) { + if rb.f.form.IsNormal([]byte(s)) { + return 1, nil + } + return 0, nil +} + +func isNormalStringF(rb *reorderBuffer, s string) (int, []byte) { + if rb.f.form.IsNormalString(s) { + return 1, nil + } + return 0, nil +} + +func TestIsNormal(t *testing.T) { + runPosTests(t, "TestIsNormalNFD1", NFD, isNormalF, isNormalTests) + runPosTests(t, "TestIsNormalNFD2", NFD, isNormalF, isNormalNFDTests) + runPosTests(t, "TestIsNormalNFC1", NFC, isNormalF, isNormalTests) + runPosTests(t, "TestIsNormalNFC2", NFC, isNormalF, isNormalNFCTests) + runPosTests(t, "TestIsNormalNFKD1", NFKD, isNormalF, isNormalTests) + runPosTests(t, "TestIsNormalNFKD2", NFKD, isNormalF, isNormalNFDTests) + runPosTests(t, "TestIsNormalNFKD3", NFKD, isNormalF, isNormalNFKXTests) + runPosTests(t, "TestIsNormalNFKC1", NFKC, isNormalF, isNormalTests) + runPosTests(t, "TestIsNormalNFKC2", NFKC, isNormalF, isNormalNFCTests) + runPosTests(t, "TestIsNormalNFKC3", NFKC, isNormalF, isNormalNFKXTests) +} + +func TestIsNormalString(t *testing.T) { + runPosTests(t, "TestIsNormalNFD1", NFD, isNormalStringF, isNormalTests) + runPosTests(t, "TestIsNormalNFD2", NFD, isNormalStringF, isNormalNFDTests) + runPosTests(t, "TestIsNormalNFC1", NFC, isNormalStringF, isNormalTests) + runPosTests(t, "TestIsNormalNFC2", NFC, isNormalStringF, isNormalNFCTests) +} + +type AppendTest struct { + left string + right string + out string +} + +type appendFunc func(f Form, out []byte, s string) []byte + +var fstr = []string{"NFC", "NFD", "NFKC", "NFKD"} + +func runNormTests(t *testing.T, name string, fn appendFunc) { + for f := NFC; f <= NFKD; f++ { + runAppendTests(t, name, f, fn, normTests[f]) + } +} + +func runAppendTests(t *testing.T, name string, f Form, fn appendFunc, tests []AppendTest) { + for i, test := range tests { + if *testn >= 0 && i != *testn { + continue + } + out := []byte(test.left) + have := string(fn(f, out, test.right)) + if len(have) != len(test.out) { + t.Errorf("%s.%s:%d: length is %d; want %d (%+q vs %+q)", fstr[f], name, i, len(have), len(test.out), pc(have), pc(test.out)) + } + if have != test.out { + k, pf := pidx(have, test.out) + t.Errorf("%s.%s:%d: \nwas %s%+q; \nwant %s%+q", fstr[f], name, i, pf, pc(have[k:]), pf, pc(test.out[k:])) + } + + // Bootstrap by normalizing input. Ensures that the various variants + // behave the same. + for g := NFC; g <= NFKD; g++ { + if f == g { + continue + } + want := g.String(test.left + test.right) + have := string(fn(g, g.AppendString(nil, test.left), test.right)) + if len(have) != len(want) { + t.Errorf("%s(%s.%s):%d: length is %d; want %d (%+q vs %+q)", fstr[g], fstr[f], name, i, len(have), len(want), pc(have), pc(want)) + } + if have != want { + k, pf := pidx(have, want) + t.Errorf("%s(%s.%s):%d: \nwas %s%+q; \nwant %s%+q", fstr[g], fstr[f], name, i, pf, pc(have[k:]), pf, pc(want[k:])) + } + } + } +} + +var normTests = [][]AppendTest{ + appendTestsNFC, + appendTestsNFD, + appendTestsNFKC, + appendTestsNFKD, +} + +var appendTestsNFC = []AppendTest{ + {"", ascii, ascii}, + {"", txt_all, txt_all}, + {"\uff9e", grave(30), "\uff9e" + grave(29) + cgj + grave(1)}, + {grave(30), "\uff9e", grave(30) + cgj + "\uff9e"}, + + // Tests designed for Iter. + { // ordering of non-composing combining characters + "", + "\u0305\u0316", + "\u0316\u0305", + }, + { // segment overflow + "", + "a" + rep(0x0305, maxNonStarters+4) + "\u0316", + "a" + rep(0x0305, maxNonStarters) + cgj + "\u0316" + rep(0x305, 4), + }, +} + +var appendTestsNFD = []AppendTest{ +// TODO: Move some of the tests here. +} + +var appendTestsNFKC = []AppendTest{ + // empty buffers + {"", "", ""}, + {"a", "", "a"}, + {"", "a", "a"}, + {"", "\u0041\u0307\u0304", "\u01E0"}, + // segment split across buffers + {"", "a\u0300b", "\u00E0b"}, + {"a", "\u0300b", "\u00E0b"}, + {"a", "\u0300\u0316", "\u00E0\u0316"}, + {"a", "\u0316\u0300", "\u00E0\u0316"}, + {"a", "\u0300a\u0300", "\u00E0\u00E0"}, + {"a", "\u0300a\u0300a\u0300", "\u00E0\u00E0\u00E0"}, + {"a", "\u0300aaa\u0300aaa\u0300", "\u00E0aa\u00E0aa\u00E0"}, + {"a\u0300", "\u0327", "\u00E0\u0327"}, + {"a\u0327", "\u0300", "\u00E0\u0327"}, + {"a\u0316", "\u0300", "\u00E0\u0316"}, + {"\u0041\u0307", "\u0304", "\u01E0"}, + // Hangul + {"", "\u110B\u1173", "\uC73C"}, + {"", "\u1103\u1161", "\uB2E4"}, + {"", "\u110B\u1173\u11B7", "\uC74C"}, + {"", "\u320E", "\x28\uAC00\x29"}, + {"", "\x28\u1100\u1161\x29", "\x28\uAC00\x29"}, + {"\u1103", "\u1161", "\uB2E4"}, + {"\u110B", "\u1173\u11B7", "\uC74C"}, + {"\u110B\u1173", "\u11B7", "\uC74C"}, + {"\uC73C", "\u11B7", "\uC74C"}, + // UTF-8 encoding split across buffers + {"a\xCC", "\x80", "\u00E0"}, + {"a\xCC", "\x80b", "\u00E0b"}, + {"a\xCC", "\x80a\u0300", "\u00E0\u00E0"}, + {"a\xCC", "\x80\x80", "\u00E0\x80"}, + {"a\xCC", "\x80\xCC", "\u00E0\xCC"}, + {"a\u0316\xCC", "\x80a\u0316\u0300", "\u00E0\u0316\u00E0\u0316"}, + // ending in incomplete UTF-8 encoding + {"", "\xCC", "\xCC"}, + {"a", "\xCC", "a\xCC"}, + {"a", "b\xCC", "ab\xCC"}, + {"\u0226", "\xCC", "\u0226\xCC"}, + // illegal runes + {"", "\x80", "\x80"}, + {"", "\x80\x80\x80", "\x80\x80\x80"}, + {"", "\xCC\x80\x80\x80", "\xCC\x80\x80\x80"}, + {"", "a\x80", "a\x80"}, + {"", "a\x80\x80\x80", "a\x80\x80\x80"}, + {"", "a\x80\x80\x80\x80\x80\x80", "a\x80\x80\x80\x80\x80\x80"}, + {"a", "\x80\x80\x80", "a\x80\x80\x80"}, + // overflow + {"", strings.Repeat("\x80", 33), strings.Repeat("\x80", 33)}, + {strings.Repeat("\x80", 33), "", strings.Repeat("\x80", 33)}, + {strings.Repeat("\x80", 33), strings.Repeat("\x80", 33), strings.Repeat("\x80", 66)}, + // overflow of combining characters + {"", grave(34), grave(30) + cgj + grave(4)}, + {"", grave(36), grave(30) + cgj + grave(6)}, + {grave(29), grave(5), grave(30) + cgj + grave(4)}, + {grave(30), grave(4), grave(30) + cgj + grave(4)}, + {grave(30), grave(3), grave(30) + cgj + grave(3)}, + {grave(30) + "\xCC", "\x80", grave(30) + cgj + grave(1)}, + {"", "\uFDFA" + grave(14), "\u0635\u0644\u0649 \u0627\u0644\u0644\u0647 \u0639\u0644\u064a\u0647 \u0648\u0633\u0644\u0645" + grave(14)}, + {"", "\uFDFA" + grave(28) + "\u0316", "\u0635\u0644\u0649 \u0627\u0644\u0644\u0647 \u0639\u0644\u064a\u0647 \u0648\u0633\u0644\u0645\u0316" + grave(28)}, + // - First rune has a trailing non-starter. + {"\u00d5", grave(30), "\u00d5" + grave(29) + cgj + grave(1)}, + // - U+FF9E decomposes into a non-starter in compatibility mode. A CGJ must be + // inserted even when FF9E starts a new segment. + {"\uff9e", grave(30), "\u3099" + grave(29) + cgj + grave(1)}, + {grave(30), "\uff9e", grave(30) + cgj + "\u3099"}, + // - Many non-starter decompositions in a row causing overflow. + {"", rep(0x340, 31), rep(0x300, 30) + cgj + "\u0300"}, + {"", rep(0xFF9E, 31), rep(0x3099, 30) + cgj + "\u3099"}, + // weird UTF-8 + {"\u00E0\xE1", "\x86", "\u00E0\xE1\x86"}, + {"a\u0300\u11B7", "\u0300", "\u00E0\u11B7\u0300"}, + {"a\u0300\u11B7\u0300", "\u0300", "\u00E0\u11B7\u0300\u0300"}, + {"\u0300", "\xF8\x80\x80\x80\x80\u0300", "\u0300\xF8\x80\x80\x80\x80\u0300"}, + {"\u0300", "\xFC\x80\x80\x80\x80\x80\u0300", "\u0300\xFC\x80\x80\x80\x80\x80\u0300"}, + {"\xF8\x80\x80\x80\x80\u0300", "\u0300", "\xF8\x80\x80\x80\x80\u0300\u0300"}, + {"\xFC\x80\x80\x80\x80\x80\u0300", "\u0300", "\xFC\x80\x80\x80\x80\x80\u0300\u0300"}, + {"\xF8\x80\x80\x80", "\x80\u0300\u0300", "\xF8\x80\x80\x80\x80\u0300\u0300"}, + + {"", strings.Repeat("a\u0316\u0300", 6), strings.Repeat("\u00E0\u0316", 6)}, + // large input. + {"", strings.Repeat("a\u0300\u0316", 4000), strings.Repeat("\u00E0\u0316", 4000)}, + {"", strings.Repeat("\x80\x80", 4000), strings.Repeat("\x80\x80", 4000)}, + {"", "\u0041\u0307\u0304", "\u01E0"}, +} + +var appendTestsNFKD = []AppendTest{ + {"", "a" + grave(64), "a" + grave(30) + cgj + grave(30) + cgj + grave(4)}, + + { // segment overflow on unchanged character + "", + "a" + grave(64) + "\u0316", + "a" + grave(30) + cgj + grave(30) + cgj + "\u0316" + grave(4), + }, + { // segment overflow on unchanged character + start value + "", + "a" + grave(98) + "\u0316", + "a" + grave(30) + cgj + grave(30) + cgj + grave(30) + cgj + "\u0316" + grave(8), + }, + { // segment overflow on decomposition. (U+0340 decomposes to U+0300.) + "", + "a" + grave(59) + "\u0340", + "a" + grave(30) + cgj + grave(30), + }, + { // segment overflow on non-starter decomposition + "", + "a" + grave(33) + "\u0340" + grave(30) + "\u0320", + "a" + grave(30) + cgj + grave(30) + cgj + "\u0320" + grave(4), + }, + { // start value after ASCII overflow + "", + rep('a', segSize) + grave(32) + "\u0320", + rep('a', segSize) + grave(30) + cgj + "\u0320" + grave(2), + }, + { // Jamo overflow + "", + "\u1100\u1161" + grave(30) + "\u0320" + grave(2), + "\u1100\u1161" + grave(29) + cgj + "\u0320" + grave(3), + }, + { // Hangul + "", + "\uac00", + "\u1100\u1161", + }, + { // Hangul overflow + "", + "\uac00" + grave(32) + "\u0320", + "\u1100\u1161" + grave(29) + cgj + "\u0320" + grave(3), + }, + { // Hangul overflow in Hangul mode. + "", + "\uac00\uac00" + grave(32) + "\u0320", + "\u1100\u1161\u1100\u1161" + grave(29) + cgj + "\u0320" + grave(3), + }, + { // Hangul overflow in Hangul mode. + "", + strings.Repeat("\uac00", 3) + grave(32) + "\u0320", + strings.Repeat("\u1100\u1161", 3) + grave(29) + cgj + "\u0320" + grave(3), + }, + { // start value after cc=0 + "", + "您您" + grave(34) + "\u0320", + "您您" + grave(30) + cgj + "\u0320" + grave(4), + }, + { // start value after normalization + "", + "\u0300\u0320a" + grave(34) + "\u0320", + "\u0320\u0300a" + grave(30) + cgj + "\u0320" + grave(4), + }, +} + +func TestAppend(t *testing.T) { + runNormTests(t, "Append", func(f Form, out []byte, s string) []byte { + return f.Append(out, []byte(s)...) + }) +} + +func TestAppendString(t *testing.T) { + runNormTests(t, "AppendString", func(f Form, out []byte, s string) []byte { + return f.AppendString(out, s) + }) +} + +func TestBytes(t *testing.T) { + runNormTests(t, "Bytes", func(f Form, out []byte, s string) []byte { + buf := []byte{} + buf = append(buf, out...) + buf = append(buf, s...) + return f.Bytes(buf) + }) +} + +func TestString(t *testing.T) { + runNormTests(t, "String", func(f Form, out []byte, s string) []byte { + outs := string(out) + s + return []byte(f.String(outs)) + }) +} + +func appendBench(f Form, in []byte) func() { + buf := make([]byte, 0, 4*len(in)) + return func() { + f.Append(buf, in...) + } +} + +func bytesBench(f Form, in []byte) func() { + return func() { + f.Bytes(in) + } +} + +func iterBench(f Form, in []byte) func() { + iter := Iter{} + return func() { + iter.Init(f, in) + for !iter.Done() { + iter.Next() + } + } +} + +func transformBench(f Form, in []byte) func() { + buf := make([]byte, 4*len(in)) + return func() { + if _, n, err := f.Transform(buf, in, true); err != nil || len(in) != n { + log.Panic(n, len(in), err) + } + } +} + +func readerBench(f Form, in []byte) func() { + buf := make([]byte, 4*len(in)) + return func() { + r := f.Reader(bytes.NewReader(in)) + var err error + for err == nil { + _, err = r.Read(buf) + } + if err != io.EOF { + panic("") + } + } +} + +func writerBench(f Form, in []byte) func() { + buf := make([]byte, 0, 4*len(in)) + return func() { + r := f.Writer(bytes.NewBuffer(buf)) + if _, err := r.Write(in); err != nil { + panic("") + } + } +} + +func appendBenchmarks(bm []func(), f Form, in []byte) []func() { + bm = append(bm, appendBench(f, in)) + bm = append(bm, iterBench(f, in)) + bm = append(bm, transformBench(f, in)) + bm = append(bm, readerBench(f, in)) + bm = append(bm, writerBench(f, in)) + return bm +} + +func doFormBenchmark(b *testing.B, inf, f Form, s string) { + b.StopTimer() + in := inf.Bytes([]byte(s)) + bm := appendBenchmarks(nil, f, in) + b.SetBytes(int64(len(in) * len(bm))) + b.StartTimer() + for i := 0; i < b.N; i++ { + for _, fn := range bm { + fn() + } + } +} + +func doSingle(b *testing.B, f func(Form, []byte) func(), s []byte) { + b.StopTimer() + fn := f(NFC, s) + b.SetBytes(int64(len(s))) + b.StartTimer() + for i := 0; i < b.N; i++ { + fn() + } +} + +var ( + smallNoChange = []byte("nörmalization") + smallChange = []byte("No\u0308rmalization") + ascii = strings.Repeat("There is nothing to change here! ", 500) +) + +func lowerBench(f Form, in []byte) func() { + // Use package strings instead of bytes as it doesn't allocate memory + // if there aren't any changes. + s := string(in) + return func() { + strings.ToLower(s) + } +} + +func BenchmarkLowerCaseNoChange(b *testing.B) { + doSingle(b, lowerBench, smallNoChange) +} +func BenchmarkLowerCaseChange(b *testing.B) { + doSingle(b, lowerBench, smallChange) +} + +func quickSpanBench(f Form, in []byte) func() { + return func() { + f.QuickSpan(in) + } +} + +func BenchmarkQuickSpanChangeNFC(b *testing.B) { + doSingle(b, quickSpanBench, smallNoChange) +} + +func BenchmarkBytesNoChangeNFC(b *testing.B) { + doSingle(b, bytesBench, smallNoChange) +} +func BenchmarkBytesChangeNFC(b *testing.B) { + doSingle(b, bytesBench, smallChange) +} + +func BenchmarkAppendNoChangeNFC(b *testing.B) { + doSingle(b, appendBench, smallNoChange) +} +func BenchmarkAppendChangeNFC(b *testing.B) { + doSingle(b, appendBench, smallChange) +} +func BenchmarkAppendLargeNFC(b *testing.B) { + doSingle(b, appendBench, txt_all_bytes) +} + +func BenchmarkIterNoChangeNFC(b *testing.B) { + doSingle(b, iterBench, smallNoChange) +} +func BenchmarkIterChangeNFC(b *testing.B) { + doSingle(b, iterBench, smallChange) +} +func BenchmarkIterLargeNFC(b *testing.B) { + doSingle(b, iterBench, txt_all_bytes) +} + +func BenchmarkTransformNoChangeNFC(b *testing.B) { + doSingle(b, transformBench, smallNoChange) +} +func BenchmarkTransformChangeNFC(b *testing.B) { + doSingle(b, transformBench, smallChange) +} +func BenchmarkTransformLargeNFC(b *testing.B) { + doSingle(b, transformBench, txt_all_bytes) +} + +func BenchmarkNormalizeAsciiNFC(b *testing.B) { + doFormBenchmark(b, NFC, NFC, ascii) +} +func BenchmarkNormalizeAsciiNFD(b *testing.B) { + doFormBenchmark(b, NFC, NFD, ascii) +} +func BenchmarkNormalizeAsciiNFKC(b *testing.B) { + doFormBenchmark(b, NFC, NFKC, ascii) +} +func BenchmarkNormalizeAsciiNFKD(b *testing.B) { + doFormBenchmark(b, NFC, NFKD, ascii) +} + +func BenchmarkNormalizeNFC2NFC(b *testing.B) { + doFormBenchmark(b, NFC, NFC, txt_all) +} +func BenchmarkNormalizeNFC2NFD(b *testing.B) { + doFormBenchmark(b, NFC, NFD, txt_all) +} +func BenchmarkNormalizeNFD2NFC(b *testing.B) { + doFormBenchmark(b, NFD, NFC, txt_all) +} +func BenchmarkNormalizeNFD2NFD(b *testing.B) { + doFormBenchmark(b, NFD, NFD, txt_all) +} + +// Hangul is often special-cased, so we test it separately. +func BenchmarkNormalizeHangulNFC2NFC(b *testing.B) { + doFormBenchmark(b, NFC, NFC, txt_kr) +} +func BenchmarkNormalizeHangulNFC2NFD(b *testing.B) { + doFormBenchmark(b, NFC, NFD, txt_kr) +} +func BenchmarkNormalizeHangulNFD2NFC(b *testing.B) { + doFormBenchmark(b, NFD, NFC, txt_kr) +} +func BenchmarkNormalizeHangulNFD2NFD(b *testing.B) { + doFormBenchmark(b, NFD, NFD, txt_kr) +} + +var forms = []Form{NFC, NFD, NFKC, NFKD} + +func doTextBenchmark(b *testing.B, s string) { + b.StopTimer() + in := []byte(s) + bm := []func(){} + for _, f := range forms { + bm = appendBenchmarks(bm, f, in) + } + b.SetBytes(int64(len(s) * len(bm))) + b.StartTimer() + for i := 0; i < b.N; i++ { + for _, f := range bm { + f() + } + } +} + +func BenchmarkCanonicalOrdering(b *testing.B) { + doTextBenchmark(b, txt_canon) +} +func BenchmarkExtendedLatin(b *testing.B) { + doTextBenchmark(b, txt_vn) +} +func BenchmarkMiscTwoByteUtf8(b *testing.B) { + doTextBenchmark(b, twoByteUtf8) +} +func BenchmarkMiscThreeByteUtf8(b *testing.B) { + doTextBenchmark(b, threeByteUtf8) +} +func BenchmarkHangul(b *testing.B) { + doTextBenchmark(b, txt_kr) +} +func BenchmarkJapanese(b *testing.B) { + doTextBenchmark(b, txt_jp) +} +func BenchmarkChinese(b *testing.B) { + doTextBenchmark(b, txt_cn) +} +func BenchmarkOverflow(b *testing.B) { + doTextBenchmark(b, overflow) +} + +var overflow = string(bytes.Repeat([]byte("\u035D"), 4096)) + "\u035B" + +// Tests sampled from the Canonical ordering tests (Part 2) of +// http://unicode.org/Public/UNIDATA/NormalizationTest.txt +const txt_canon = `\u0061\u0315\u0300\u05AE\u0300\u0062 \u0061\u0300\u0315\u0300\u05AE\u0062 +\u0061\u0302\u0315\u0300\u05AE\u0062 \u0061\u0307\u0315\u0300\u05AE\u0062 +\u0061\u0315\u0300\u05AE\u030A\u0062 \u0061\u059A\u0316\u302A\u031C\u0062 +\u0061\u032E\u059A\u0316\u302A\u0062 \u0061\u0338\u093C\u0334\u0062 +\u0061\u059A\u0316\u302A\u0339 \u0061\u0341\u0315\u0300\u05AE\u0062 +\u0061\u0348\u059A\u0316\u302A\u0062 \u0061\u0361\u0345\u035D\u035C\u0062 +\u0061\u0366\u0315\u0300\u05AE\u0062 \u0061\u0315\u0300\u05AE\u0486\u0062 +\u0061\u05A4\u059A\u0316\u302A\u0062 \u0061\u0315\u0300\u05AE\u0613\u0062 +\u0061\u0315\u0300\u05AE\u0615\u0062 \u0061\u0617\u0315\u0300\u05AE\u0062 +\u0061\u0619\u0618\u064D\u064E\u0062 \u0061\u0315\u0300\u05AE\u0654\u0062 +\u0061\u0315\u0300\u05AE\u06DC\u0062 \u0061\u0733\u0315\u0300\u05AE\u0062 +\u0061\u0744\u059A\u0316\u302A\u0062 \u0061\u0315\u0300\u05AE\u0745\u0062 +\u0061\u09CD\u05B0\u094D\u3099\u0062 \u0061\u0E38\u0E48\u0E38\u0C56\u0062 +\u0061\u0EB8\u0E48\u0E38\u0E49\u0062 \u0061\u0F72\u0F71\u0EC8\u0F71\u0062 +\u0061\u1039\u05B0\u094D\u3099\u0062 \u0061\u05B0\u094D\u3099\u1A60\u0062 +\u0061\u3099\u093C\u0334\u1BE6\u0062 \u0061\u3099\u093C\u0334\u1C37\u0062 +\u0061\u1CD9\u059A\u0316\u302A\u0062 \u0061\u2DED\u0315\u0300\u05AE\u0062 +\u0061\u2DEF\u0315\u0300\u05AE\u0062 \u0061\u302D\u302E\u059A\u0316\u0062` + +// 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.` + +// 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 = `Αναφορά Δημιουργού — Θα πρέπει να κάνετε την αναφορά στο έργο με τον +τρόπο που έχει οριστεί από το δημιουργό ή το χορηγούντο την άδεια +(χωρίς όμως να εννοείται με οποιονδήποτε τρόπο ότι εγκρίνουν εσάς ή +τη χρήση του έργου από εσάς). Παρόμοια Διανομή — Εάν αλλοιώσετε, +τροποποιήσετε ή δημιουργήσετε περαιτέρω βασισμένοι στο έργο θα +μπορείτε να διανέμετε το έργο που θα προκύψει μόνο με την ίδια ή +παρόμοια άδεια.` + +// Taken from http://creativecommons.org/licenses/by-sa/3.0/deed.ar +const txt_ar = `بموجب الشروط التالية نسب المصنف — يجب عليك أن +تنسب العمل بالطريقة التي تحددها المؤلف أو المرخص (ولكن ليس بأي حال من +الأحوال أن توحي وتقترح بتحول أو استخدامك للعمل). +المشاركة على قدم المساواة — إذا كنت يعدل ، والتغيير ، أو الاستفادة +من هذا العمل ، قد ينتج عن توزيع العمل إلا في ظل تشابه او تطابق فى واحد +لهذا الترخيص.` + +// Taken from http://creativecommons.org/licenses/by-sa/1.0/il/ +const txt_il = `בכפוף לתנאים הבאים: ייחוס — עליך לייחס את היצירה (לתת קרדיט) באופן +המצויין על-ידי היוצר או מעניק הרישיון (אך לא בשום אופן המרמז על כך +שהם תומכים בך או בשימוש שלך ביצירה). שיתוף זהה — אם תחליט/י לשנות, +לעבד או ליצור יצירה נגזרת בהסתמך על יצירה זו, תוכל/י להפיץ את יצירתך +החדשה רק תחת אותו הרישיון או רישיון דומה לרישיון זה.` + +const twoByteUtf8 = txt_ru + txt_gr + txt_ar + txt_il + +// Taken from http://creativecommons.org/licenses/by-sa/2.0/kr/ +const txt_kr = `다음과 같은 조건을 따라야 합니다: 저작자표시 +(Attribution) — 저작자나 이용허락자가 정한 방법으로 저작물의 +원저작자를 표시하여야 합니다(그러나 원저작자가 이용자나 이용자의 +이용을 보증하거나 추천한다는 의미로 표시해서는 안됩니다). +동일조건변경허락 — 이 저작물을 이용하여 만든 이차적 저작물에는 본 +라이선스와 동일한 라이선스를 적용해야 합니다.` + +// Taken from http://creativecommons.org/licenses/by-sa/3.0/th/ +const txt_th = `ภายใต้เงื่อนไข ดังต่อไปนี้ : แสดงที่มา — คุณต้องแสดงที่ +มาของงานดังกล่าว ตามรูปแบบที่ผู้สร้างสรรค์หรือผู้อนุญาตกำหนด (แต่ +ไม่ใช่ในลักษณะที่ว่า พวกเขาสนับสนุนคุณหรือสนับสนุนการที่ +คุณนำงานไปใช้) อนุญาตแบบเดียวกัน — หากคุณดัดแปลง เปลี่ยนรูป หรื +อต่อเติมงานนี้ คุณต้องใช้สัญญาอนุญาตแบบเดียวกันหรือแบบที่เหมื +อนกับสัญญาอนุญาตที่ใช้กับงานนี้เท่านั้น` + +const threeByteUtf8 = txt_th + +// Taken from http://creativecommons.org/licenses/by-sa/2.0/jp/ +const txt_jp = `あなたの従うべき条件は以下の通りです。 +表示 — あなたは原著作者のクレジットを表示しなければなりません。 +継承 — もしあなたがこの作品を改変、変形または加工した場合、 +あなたはその結果生じた作品をこの作品と同一の許諾条件の下でのみ +頒布することができます。` + +// http://creativecommons.org/licenses/by-sa/2.5/cn/ +const txt_cn = `您可以自由: 复制、发行、展览、表演、放映、 +广播或通过信息网络传播本作品 创作演绎作品 +对本作品进行商业性使用 惟须遵守下列条件: +署名 — 您必须按照作者或者许可人指定的方式对作品进行署名。 +相同方式共享 — 如果您改变、转换本作品或者以本作品为基础进行创作, +您只能采用与本协议相同的许可协议发布基于本作品的演绎作品。` + +const txt_cjk = txt_cn + txt_jp + txt_kr +const txt_all = txt_vn + twoByteUtf8 + threeByteUtf8 + txt_cjk + +var txt_all_bytes = []byte(txt_all) diff --git a/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/normregtest.go b/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/normregtest.go new file mode 100644 index 000000000..ab07c68d5 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/normregtest.go @@ -0,0 +1,318 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build ignore + +package main + +import ( + "bufio" + "bytes" + "flag" + "fmt" + "log" + "net/http" + "os" + "path" + "regexp" + "runtime" + "strconv" + "strings" + "time" + "unicode" + "unicode/utf8" + + "code.google.com/p/go.text/unicode/norm" +) + +func main() { + flag.Parse() + loadTestData() + CharacterByCharacterTests() + StandardTests() + PerformanceTest() + if errorCount == 0 { + fmt.Println("PASS") + } +} + +const file = "NormalizationTest.txt" + +var url = flag.String("url", + "http://www.unicode.org/Public/"+unicode.Version+"/ucd/"+file, + "URL of Unicode database directory") +var localFiles = flag.Bool("local", + false, + "data files have been copied to the current directory; for debugging only") + +var logger = log.New(os.Stderr, "", log.Lshortfile) + +// This regression test runs the test set in NormalizationTest.txt +// (taken from http://www.unicode.org/Public//ucd/). +// +// NormalizationTest.txt has form: +// @Part0 # Specific cases +// # +// 1E0A;1E0A;0044 0307;1E0A;0044 0307; # (Ḋ; Ḋ; D◌̇; Ḋ; D◌̇; ) LATIN CAPITAL LETTER D WITH DOT ABOVE +// 1E0C;1E0C;0044 0323;1E0C;0044 0323; # (Ḍ; Ḍ; D◌̣; Ḍ; D◌̣; ) LATIN CAPITAL LETTER D WITH DOT BELOW +// +// Each test has 5 columns (c1, c2, c3, c4, c5), where +// (c1, c2, c3, c4, c5) == (c1, NFC(c1), NFD(c1), NFKC(c1), NFKD(c1)) +// +// CONFORMANCE: +// 1. The following invariants must be true for all conformant implementations +// +// NFC +// c2 == NFC(c1) == NFC(c2) == NFC(c3) +// c4 == NFC(c4) == NFC(c5) +// +// NFD +// c3 == NFD(c1) == NFD(c2) == NFD(c3) +// c5 == NFD(c4) == NFD(c5) +// +// NFKC +// c4 == NFKC(c1) == NFKC(c2) == NFKC(c3) == NFKC(c4) == NFKC(c5) +// +// NFKD +// c5 == NFKD(c1) == NFKD(c2) == NFKD(c3) == NFKD(c4) == NFKD(c5) +// +// 2. For every code point X assigned in this version of Unicode that is not +// specifically listed in Part 1, the following invariants must be true +// for all conformant implementations: +// +// X == NFC(X) == NFD(X) == NFKC(X) == NFKD(X) +// + +// Column types. +const ( + cRaw = iota + cNFC + cNFD + cNFKC + cNFKD + cMaxColumns +) + +// Holds data from NormalizationTest.txt +var part []Part + +type Part struct { + name string + number int + tests []Test +} + +type Test struct { + name string + partnr int + number int + r rune // used for character by character test + cols [cMaxColumns]string // Each has 5 entries, see below. +} + +func (t Test) Name() string { + if t.number < 0 { + return part[t.partnr].name + } + return fmt.Sprintf("%s:%d", part[t.partnr].name, t.number) +} + +var partRe = regexp.MustCompile(`@Part(\d) # (.*)$`) +var testRe = regexp.MustCompile(`^` + strings.Repeat(`([\dA-F ]+);`, 5) + ` # (.*)$`) + +var counter int + +// Load the data form NormalizationTest.txt +func loadTestData() { + if *localFiles { + pwd, _ := os.Getwd() + *url = "file://" + path.Join(pwd, file) + } + t := &http.Transport{} + t.RegisterProtocol("file", http.NewFileTransport(http.Dir("/"))) + c := &http.Client{Transport: t} + resp, err := c.Get(*url) + if err != nil { + logger.Fatal(err) + } + if resp.StatusCode != 200 { + logger.Fatal("bad GET status for "+file, resp.Status) + } + f := resp.Body + defer f.Close() + scanner := bufio.NewScanner(f) + for scanner.Scan() { + line := scanner.Text() + if len(line) == 0 || line[0] == '#' { + continue + } + m := partRe.FindStringSubmatch(line) + if m != nil { + if len(m) < 3 { + logger.Fatal("Failed to parse Part: ", line) + } + i, err := strconv.Atoi(m[1]) + if err != nil { + logger.Fatal(err) + } + name := m[2] + part = append(part, Part{name: name[:len(name)-1], number: i}) + continue + } + m = testRe.FindStringSubmatch(line) + if m == nil || len(m) < 7 { + logger.Fatalf(`Failed to parse: "%s" result: %#v`, line, m) + } + test := Test{name: m[6], partnr: len(part) - 1, number: counter} + counter++ + for j := 1; j < len(m)-1; j++ { + for _, split := range strings.Split(m[j], " ") { + r, err := strconv.ParseUint(split, 16, 64) + if err != nil { + logger.Fatal(err) + } + if test.r == 0 { + // save for CharacterByCharacterTests + test.r = rune(r) + } + var buf [utf8.UTFMax]byte + sz := utf8.EncodeRune(buf[:], rune(r)) + test.cols[j-1] += string(buf[:sz]) + } + } + part := &part[len(part)-1] + part.tests = append(part.tests, test) + } + if scanner.Err() != nil { + logger.Fatal(scanner.Err()) + } +} + +var fstr = []string{"NFC", "NFD", "NFKC", "NFKD"} + +var errorCount int + +func cmpResult(t *Test, name string, f norm.Form, gold, test, result string) { + if gold != result { + errorCount++ + if errorCount > 20 { + return + } + logger.Printf("%s:%s: %s(%+q)=%+q; want %+q: %s", + t.Name(), name, fstr[f], test, result, gold, t.name) + } +} + +func cmpIsNormal(t *Test, name string, f norm.Form, test string, result, want bool) { + if result != want { + errorCount++ + if errorCount > 20 { + return + } + logger.Printf("%s:%s: %s(%+q)=%v; want %v", t.Name(), name, fstr[f], test, result, want) + } +} + +func doTest(t *Test, f norm.Form, gold, test string) { + testb := []byte(test) + result := f.Bytes(testb) + cmpResult(t, "Bytes", f, gold, test, string(result)) + + sresult := f.String(test) + cmpResult(t, "String", f, gold, test, sresult) + + acc := []byte{} + i := norm.Iter{} + i.InitString(f, test) + for !i.Done() { + acc = append(acc, i.Next()...) + } + cmpResult(t, "Iter.Next", f, gold, test, string(acc)) + + buf := make([]byte, 128) + acc = nil + for p := 0; p < len(testb); { + nDst, nSrc, _ := f.Transform(buf, testb[p:], true) + acc = append(acc, buf[:nDst]...) + p += nSrc + } + cmpResult(t, "Transform", f, gold, test, string(acc)) + + for i := range test { + out := f.Append(f.Bytes([]byte(test[:i])), []byte(test[i:])...) + cmpResult(t, fmt.Sprintf(":Append:%d", i), f, gold, test, string(out)) + } + cmpIsNormal(t, "IsNormal", f, test, f.IsNormal([]byte(test)), test == gold) + cmpIsNormal(t, "IsNormalString", f, test, f.IsNormalString(test), test == gold) +} + +func doConformanceTests(t *Test, partn int) { + for i := 0; i <= 2; i++ { + doTest(t, norm.NFC, t.cols[1], t.cols[i]) + doTest(t, norm.NFD, t.cols[2], t.cols[i]) + doTest(t, norm.NFKC, t.cols[3], t.cols[i]) + doTest(t, norm.NFKD, t.cols[4], t.cols[i]) + } + for i := 3; i <= 4; i++ { + doTest(t, norm.NFC, t.cols[3], t.cols[i]) + doTest(t, norm.NFD, t.cols[4], t.cols[i]) + doTest(t, norm.NFKC, t.cols[3], t.cols[i]) + doTest(t, norm.NFKD, t.cols[4], t.cols[i]) + } +} + +func CharacterByCharacterTests() { + tests := part[1].tests + var last rune = 0 + for i := 0; i <= len(tests); i++ { // last one is special case + var r rune + if i == len(tests) { + r = 0x2FA1E // Don't have to go to 0x10FFFF + } else { + r = tests[i].r + } + for last++; last < r; last++ { + // Check all characters that were not explicitly listed in the test. + t := &Test{partnr: 1, number: -1} + char := string(last) + doTest(t, norm.NFC, char, char) + doTest(t, norm.NFD, char, char) + doTest(t, norm.NFKC, char, char) + doTest(t, norm.NFKD, char, char) + } + if i < len(tests) { + doConformanceTests(&tests[i], 1) + } + } +} + +func StandardTests() { + for _, j := range []int{0, 2, 3} { + for _, test := range part[j].tests { + doConformanceTests(&test, j) + } + } +} + +// PerformanceTest verifies that normalization is O(n). If any of the +// code does not properly check for maxCombiningChars, normalization +// may exhibit O(n**2) behavior. +func PerformanceTest() { + runtime.GOMAXPROCS(2) + success := make(chan bool, 1) + go func() { + buf := bytes.Repeat([]byte("\u035D"), 1024*1024) + buf = append(buf, "\u035B"...) + norm.NFC.Append(nil, buf...) + success <- true + }() + timeout := time.After(1 * time.Second) + select { + case <-success: + // test completed before the timeout + case <-timeout: + errorCount++ + logger.Printf(`unexpectedly long time to complete PerformanceTest`) + } +} diff --git a/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/readwriter.go b/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/readwriter.go new file mode 100644 index 000000000..4fa0e04b2 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/readwriter.go @@ -0,0 +1,126 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package norm + +import "io" + +type normWriter struct { + rb reorderBuffer + w io.Writer + buf []byte +} + +// Write implements the standard write interface. If the last characters are +// not at a normalization boundary, the bytes will be buffered for the next +// write. The remaining bytes will be written on close. +func (w *normWriter) Write(data []byte) (n int, err error) { + // Process data in pieces to keep w.buf size bounded. + const chunk = 4000 + + for len(data) > 0 { + // Normalize into w.buf. + m := len(data) + if m > chunk { + m = chunk + } + w.rb.src = inputBytes(data[:m]) + w.rb.nsrc = m + w.buf = doAppend(&w.rb, w.buf, 0) + data = data[m:] + n += m + + // Write out complete prefix, save remainder. + // Note that lastBoundary looks back at most 31 runes. + i := lastBoundary(&w.rb.f, w.buf) + if i == -1 { + i = 0 + } + if i > 0 { + if _, err = w.w.Write(w.buf[:i]); err != nil { + break + } + bn := copy(w.buf, w.buf[i:]) + w.buf = w.buf[:bn] + } + } + return n, err +} + +// Close forces data that remains in the buffer to be written. +func (w *normWriter) Close() error { + if len(w.buf) > 0 { + _, err := w.w.Write(w.buf) + if err != nil { + return err + } + } + return nil +} + +// Writer returns a new writer that implements Write(b) +// by writing f(b) to w. The returned writer may use an +// an internal buffer to maintain state across Write calls. +// Calling its Close method writes any buffered data to w. +func (f Form) Writer(w io.Writer) io.WriteCloser { + wr := &normWriter{rb: reorderBuffer{}, w: w} + wr.rb.init(f, nil) + return wr +} + +type normReader struct { + rb reorderBuffer + r io.Reader + inbuf []byte + outbuf []byte + bufStart int + lastBoundary int + err error +} + +// Read implements the standard read interface. +func (r *normReader) Read(p []byte) (int, error) { + for { + if r.lastBoundary-r.bufStart > 0 { + n := copy(p, r.outbuf[r.bufStart:r.lastBoundary]) + r.bufStart += n + if r.lastBoundary-r.bufStart > 0 { + return n, nil + } + return n, r.err + } + if r.err != nil { + return 0, r.err + } + outn := copy(r.outbuf, r.outbuf[r.lastBoundary:]) + r.outbuf = r.outbuf[0:outn] + r.bufStart = 0 + + n, err := r.r.Read(r.inbuf) + r.rb.src = inputBytes(r.inbuf[0:n]) + r.rb.nsrc, r.err = n, err + if n > 0 { + r.outbuf = doAppend(&r.rb, r.outbuf, 0) + } + if err == io.EOF { + r.lastBoundary = len(r.outbuf) + } else { + r.lastBoundary = lastBoundary(&r.rb.f, r.outbuf) + if r.lastBoundary == -1 { + r.lastBoundary = 0 + } + } + } + panic("should not reach here") +} + +// Reader returns a new reader that implements Read +// by reading data from r and returning f(data). +func (f Form) Reader(r io.Reader) io.Reader { + const chunk = 4000 + buf := make([]byte, chunk) + rr := &normReader{rb: reorderBuffer{}, r: r, inbuf: buf} + rr.rb.init(f, buf) + return rr +} diff --git a/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/readwriter_test.go b/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/readwriter_test.go new file mode 100644 index 000000000..b7756ba24 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/readwriter_test.go @@ -0,0 +1,56 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package norm + +import ( + "bytes" + "fmt" + "testing" +) + +var bufSizes = []int{1, 2, 3, 4, 5, 6, 7, 8, 100, 101, 102, 103, 4000, 4001, 4002, 4003} + +func readFunc(size int) appendFunc { + return func(f Form, out []byte, s string) []byte { + out = append(out, s...) + r := f.Reader(bytes.NewBuffer(out)) + buf := make([]byte, size) + result := []byte{} + for n, err := 0, error(nil); err == nil; { + n, err = r.Read(buf) + result = append(result, buf[:n]...) + } + return result + } +} + +func TestReader(t *testing.T) { + for _, s := range bufSizes { + name := fmt.Sprintf("TestReader%d", s) + runNormTests(t, name, readFunc(s)) + } +} + +func writeFunc(size int) appendFunc { + return func(f Form, out []byte, s string) []byte { + in := append(out, s...) + result := new(bytes.Buffer) + w := f.Writer(result) + buf := make([]byte, size) + for n := 0; len(in) > 0; in = in[n:] { + n = copy(buf, in) + _, _ = w.Write(buf[:n]) + } + w.Close() + return result.Bytes() + } +} + +func TestWriter(t *testing.T) { + for _, s := range bufSizes { + name := fmt.Sprintf("TestWriter%d", s) + runNormTests(t, name, writeFunc(s)) + } +} diff --git a/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/tables.go b/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/tables.go new file mode 100644 index 000000000..4d8afe43d --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/tables.go @@ -0,0 +1,6989 @@ +// Generated by running +// maketables --tables=all --url=http://www.unicode.org/Public/6.3.0/ucd/ +// DO NOT EDIT + +package norm + +const ( + // Version is the Unicode edition from which the tables are derived. + Version = "6.3.0" + + // MaxTransformChunkSize indicates the maximum number of bytes that Transform + // may need to write atomically for any Form. Making a destination buffer at + // least this size ensures that Transform can always make progress and that + // the user does not need to grow the buffer on an ErrShortDst. + MaxTransformChunkSize = 35 + maxNonStarters*4 +) + +var ccc = [55]uint8{ + 0, 1, 7, 8, 9, 10, 11, 12, + 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, + 84, 91, 103, 107, 118, 122, 129, 130, + 132, 202, 214, 216, 218, 220, 222, 224, + 226, 228, 230, 232, 233, 234, 240, +} + +const ( + firstMulti = 0x18CC + firstCCC = 0x2E71 + endMulti = 0x2F47 + firstLeadingCCC = 0x4995 + firstCCCZeroExcept = 0x49AB + firstStarterWithNLead = 0x49D2 + lastDecomp = 0x49D4 + maxDecomp = 0x8000 +) + +// decomps: 18900 bytes +var decomps = [...]byte{ + // Bytes 0 - 3f + 0x00, 0x41, 0x20, 0x41, 0x21, 0x41, 0x22, 0x41, + 0x23, 0x41, 0x24, 0x41, 0x25, 0x41, 0x26, 0x41, + 0x27, 0x41, 0x28, 0x41, 0x29, 0x41, 0x2A, 0x41, + 0x2B, 0x41, 0x2C, 0x41, 0x2D, 0x41, 0x2E, 0x41, + 0x2F, 0x41, 0x30, 0x41, 0x31, 0x41, 0x32, 0x41, + 0x33, 0x41, 0x34, 0x41, 0x35, 0x41, 0x36, 0x41, + 0x37, 0x41, 0x38, 0x41, 0x39, 0x41, 0x3A, 0x41, + 0x3B, 0x41, 0x3C, 0x41, 0x3D, 0x41, 0x3E, 0x41, + // Bytes 40 - 7f + 0x3F, 0x41, 0x40, 0x41, 0x41, 0x41, 0x42, 0x41, + 0x43, 0x41, 0x44, 0x41, 0x45, 0x41, 0x46, 0x41, + 0x47, 0x41, 0x48, 0x41, 0x49, 0x41, 0x4A, 0x41, + 0x4B, 0x41, 0x4C, 0x41, 0x4D, 0x41, 0x4E, 0x41, + 0x4F, 0x41, 0x50, 0x41, 0x51, 0x41, 0x52, 0x41, + 0x53, 0x41, 0x54, 0x41, 0x55, 0x41, 0x56, 0x41, + 0x57, 0x41, 0x58, 0x41, 0x59, 0x41, 0x5A, 0x41, + 0x5B, 0x41, 0x5C, 0x41, 0x5D, 0x41, 0x5E, 0x41, + // Bytes 80 - bf + 0x5F, 0x41, 0x60, 0x41, 0x61, 0x41, 0x62, 0x41, + 0x63, 0x41, 0x64, 0x41, 0x65, 0x41, 0x66, 0x41, + 0x67, 0x41, 0x68, 0x41, 0x69, 0x41, 0x6A, 0x41, + 0x6B, 0x41, 0x6C, 0x41, 0x6D, 0x41, 0x6E, 0x41, + 0x6F, 0x41, 0x70, 0x41, 0x71, 0x41, 0x72, 0x41, + 0x73, 0x41, 0x74, 0x41, 0x75, 0x41, 0x76, 0x41, + 0x77, 0x41, 0x78, 0x41, 0x79, 0x41, 0x7A, 0x41, + 0x7B, 0x41, 0x7C, 0x41, 0x7D, 0x41, 0x7E, 0x42, + // Bytes c0 - ff + 0xC2, 0xA2, 0x42, 0xC2, 0xA3, 0x42, 0xC2, 0xA5, + 0x42, 0xC2, 0xA6, 0x42, 0xC2, 0xAC, 0x42, 0xC2, + 0xB7, 0x42, 0xC3, 0x86, 0x42, 0xC3, 0xB0, 0x42, + 0xC4, 0xA6, 0x42, 0xC4, 0xA7, 0x42, 0xC4, 0xB1, + 0x42, 0xC5, 0x8B, 0x42, 0xC5, 0x93, 0x42, 0xC6, + 0x8E, 0x42, 0xC6, 0x90, 0x42, 0xC6, 0xAB, 0x42, + 0xC8, 0xA2, 0x42, 0xC8, 0xB7, 0x42, 0xC9, 0x90, + 0x42, 0xC9, 0x91, 0x42, 0xC9, 0x92, 0x42, 0xC9, + // Bytes 100 - 13f + 0x94, 0x42, 0xC9, 0x95, 0x42, 0xC9, 0x99, 0x42, + 0xC9, 0x9B, 0x42, 0xC9, 0x9C, 0x42, 0xC9, 0x9F, + 0x42, 0xC9, 0xA1, 0x42, 0xC9, 0xA3, 0x42, 0xC9, + 0xA5, 0x42, 0xC9, 0xA6, 0x42, 0xC9, 0xA8, 0x42, + 0xC9, 0xA9, 0x42, 0xC9, 0xAA, 0x42, 0xC9, 0xAD, + 0x42, 0xC9, 0xAF, 0x42, 0xC9, 0xB0, 0x42, 0xC9, + 0xB1, 0x42, 0xC9, 0xB2, 0x42, 0xC9, 0xB3, 0x42, + 0xC9, 0xB4, 0x42, 0xC9, 0xB5, 0x42, 0xC9, 0xB8, + // Bytes 140 - 17f + 0x42, 0xC9, 0xB9, 0x42, 0xC9, 0xBB, 0x42, 0xCA, + 0x81, 0x42, 0xCA, 0x82, 0x42, 0xCA, 0x83, 0x42, + 0xCA, 0x89, 0x42, 0xCA, 0x8A, 0x42, 0xCA, 0x8B, + 0x42, 0xCA, 0x8C, 0x42, 0xCA, 0x90, 0x42, 0xCA, + 0x91, 0x42, 0xCA, 0x92, 0x42, 0xCA, 0x95, 0x42, + 0xCA, 0x9D, 0x42, 0xCA, 0x9F, 0x42, 0xCA, 0xB9, + 0x42, 0xCE, 0x91, 0x42, 0xCE, 0x92, 0x42, 0xCE, + 0x93, 0x42, 0xCE, 0x94, 0x42, 0xCE, 0x95, 0x42, + // Bytes 180 - 1bf + 0xCE, 0x96, 0x42, 0xCE, 0x97, 0x42, 0xCE, 0x98, + 0x42, 0xCE, 0x99, 0x42, 0xCE, 0x9A, 0x42, 0xCE, + 0x9B, 0x42, 0xCE, 0x9C, 0x42, 0xCE, 0x9D, 0x42, + 0xCE, 0x9E, 0x42, 0xCE, 0x9F, 0x42, 0xCE, 0xA0, + 0x42, 0xCE, 0xA1, 0x42, 0xCE, 0xA3, 0x42, 0xCE, + 0xA4, 0x42, 0xCE, 0xA5, 0x42, 0xCE, 0xA6, 0x42, + 0xCE, 0xA7, 0x42, 0xCE, 0xA8, 0x42, 0xCE, 0xA9, + 0x42, 0xCE, 0xB1, 0x42, 0xCE, 0xB2, 0x42, 0xCE, + // Bytes 1c0 - 1ff + 0xB3, 0x42, 0xCE, 0xB4, 0x42, 0xCE, 0xB5, 0x42, + 0xCE, 0xB6, 0x42, 0xCE, 0xB7, 0x42, 0xCE, 0xB8, + 0x42, 0xCE, 0xB9, 0x42, 0xCE, 0xBA, 0x42, 0xCE, + 0xBB, 0x42, 0xCE, 0xBC, 0x42, 0xCE, 0xBD, 0x42, + 0xCE, 0xBE, 0x42, 0xCE, 0xBF, 0x42, 0xCF, 0x80, + 0x42, 0xCF, 0x81, 0x42, 0xCF, 0x82, 0x42, 0xCF, + 0x83, 0x42, 0xCF, 0x84, 0x42, 0xCF, 0x85, 0x42, + 0xCF, 0x86, 0x42, 0xCF, 0x87, 0x42, 0xCF, 0x88, + // Bytes 200 - 23f + 0x42, 0xCF, 0x89, 0x42, 0xCF, 0x9C, 0x42, 0xCF, + 0x9D, 0x42, 0xD0, 0xBD, 0x42, 0xD7, 0x90, 0x42, + 0xD7, 0x91, 0x42, 0xD7, 0x92, 0x42, 0xD7, 0x93, + 0x42, 0xD7, 0x94, 0x42, 0xD7, 0x9B, 0x42, 0xD7, + 0x9C, 0x42, 0xD7, 0x9D, 0x42, 0xD7, 0xA2, 0x42, + 0xD7, 0xA8, 0x42, 0xD7, 0xAA, 0x42, 0xD8, 0xA1, + 0x42, 0xD8, 0xA7, 0x42, 0xD8, 0xA8, 0x42, 0xD8, + 0xA9, 0x42, 0xD8, 0xAA, 0x42, 0xD8, 0xAB, 0x42, + // Bytes 240 - 27f + 0xD8, 0xAC, 0x42, 0xD8, 0xAD, 0x42, 0xD8, 0xAE, + 0x42, 0xD8, 0xAF, 0x42, 0xD8, 0xB0, 0x42, 0xD8, + 0xB1, 0x42, 0xD8, 0xB2, 0x42, 0xD8, 0xB3, 0x42, + 0xD8, 0xB4, 0x42, 0xD8, 0xB5, 0x42, 0xD8, 0xB6, + 0x42, 0xD8, 0xB7, 0x42, 0xD8, 0xB8, 0x42, 0xD8, + 0xB9, 0x42, 0xD8, 0xBA, 0x42, 0xD9, 0x81, 0x42, + 0xD9, 0x82, 0x42, 0xD9, 0x83, 0x42, 0xD9, 0x84, + 0x42, 0xD9, 0x85, 0x42, 0xD9, 0x86, 0x42, 0xD9, + // Bytes 280 - 2bf + 0x87, 0x42, 0xD9, 0x88, 0x42, 0xD9, 0x89, 0x42, + 0xD9, 0x8A, 0x42, 0xD9, 0xAE, 0x42, 0xD9, 0xAF, + 0x42, 0xD9, 0xB1, 0x42, 0xD9, 0xB9, 0x42, 0xD9, + 0xBA, 0x42, 0xD9, 0xBB, 0x42, 0xD9, 0xBE, 0x42, + 0xD9, 0xBF, 0x42, 0xDA, 0x80, 0x42, 0xDA, 0x83, + 0x42, 0xDA, 0x84, 0x42, 0xDA, 0x86, 0x42, 0xDA, + 0x87, 0x42, 0xDA, 0x88, 0x42, 0xDA, 0x8C, 0x42, + 0xDA, 0x8D, 0x42, 0xDA, 0x8E, 0x42, 0xDA, 0x91, + // Bytes 2c0 - 2ff + 0x42, 0xDA, 0x98, 0x42, 0xDA, 0xA1, 0x42, 0xDA, + 0xA4, 0x42, 0xDA, 0xA6, 0x42, 0xDA, 0xA9, 0x42, + 0xDA, 0xAD, 0x42, 0xDA, 0xAF, 0x42, 0xDA, 0xB1, + 0x42, 0xDA, 0xB3, 0x42, 0xDA, 0xBA, 0x42, 0xDA, + 0xBB, 0x42, 0xDA, 0xBE, 0x42, 0xDB, 0x81, 0x42, + 0xDB, 0x85, 0x42, 0xDB, 0x86, 0x42, 0xDB, 0x87, + 0x42, 0xDB, 0x88, 0x42, 0xDB, 0x89, 0x42, 0xDB, + 0x8B, 0x42, 0xDB, 0x8C, 0x42, 0xDB, 0x90, 0x42, + // Bytes 300 - 33f + 0xDB, 0x92, 0x43, 0xE0, 0xBC, 0x8B, 0x43, 0xE1, + 0x83, 0x9C, 0x43, 0xE1, 0x84, 0x80, 0x43, 0xE1, + 0x84, 0x81, 0x43, 0xE1, 0x84, 0x82, 0x43, 0xE1, + 0x84, 0x83, 0x43, 0xE1, 0x84, 0x84, 0x43, 0xE1, + 0x84, 0x85, 0x43, 0xE1, 0x84, 0x86, 0x43, 0xE1, + 0x84, 0x87, 0x43, 0xE1, 0x84, 0x88, 0x43, 0xE1, + 0x84, 0x89, 0x43, 0xE1, 0x84, 0x8A, 0x43, 0xE1, + 0x84, 0x8B, 0x43, 0xE1, 0x84, 0x8C, 0x43, 0xE1, + // Bytes 340 - 37f + 0x84, 0x8D, 0x43, 0xE1, 0x84, 0x8E, 0x43, 0xE1, + 0x84, 0x8F, 0x43, 0xE1, 0x84, 0x90, 0x43, 0xE1, + 0x84, 0x91, 0x43, 0xE1, 0x84, 0x92, 0x43, 0xE1, + 0x84, 0x94, 0x43, 0xE1, 0x84, 0x95, 0x43, 0xE1, + 0x84, 0x9A, 0x43, 0xE1, 0x84, 0x9C, 0x43, 0xE1, + 0x84, 0x9D, 0x43, 0xE1, 0x84, 0x9E, 0x43, 0xE1, + 0x84, 0xA0, 0x43, 0xE1, 0x84, 0xA1, 0x43, 0xE1, + 0x84, 0xA2, 0x43, 0xE1, 0x84, 0xA3, 0x43, 0xE1, + // Bytes 380 - 3bf + 0x84, 0xA7, 0x43, 0xE1, 0x84, 0xA9, 0x43, 0xE1, + 0x84, 0xAB, 0x43, 0xE1, 0x84, 0xAC, 0x43, 0xE1, + 0x84, 0xAD, 0x43, 0xE1, 0x84, 0xAE, 0x43, 0xE1, + 0x84, 0xAF, 0x43, 0xE1, 0x84, 0xB2, 0x43, 0xE1, + 0x84, 0xB6, 0x43, 0xE1, 0x85, 0x80, 0x43, 0xE1, + 0x85, 0x87, 0x43, 0xE1, 0x85, 0x8C, 0x43, 0xE1, + 0x85, 0x97, 0x43, 0xE1, 0x85, 0x98, 0x43, 0xE1, + 0x85, 0x99, 0x43, 0xE1, 0x85, 0xA0, 0x43, 0xE1, + // Bytes 3c0 - 3ff + 0x85, 0xA1, 0x43, 0xE1, 0x85, 0xA2, 0x43, 0xE1, + 0x85, 0xA3, 0x43, 0xE1, 0x85, 0xA4, 0x43, 0xE1, + 0x85, 0xA5, 0x43, 0xE1, 0x85, 0xA6, 0x43, 0xE1, + 0x85, 0xA7, 0x43, 0xE1, 0x85, 0xA8, 0x43, 0xE1, + 0x85, 0xA9, 0x43, 0xE1, 0x85, 0xAA, 0x43, 0xE1, + 0x85, 0xAB, 0x43, 0xE1, 0x85, 0xAC, 0x43, 0xE1, + 0x85, 0xAD, 0x43, 0xE1, 0x85, 0xAE, 0x43, 0xE1, + 0x85, 0xAF, 0x43, 0xE1, 0x85, 0xB0, 0x43, 0xE1, + // Bytes 400 - 43f + 0x85, 0xB1, 0x43, 0xE1, 0x85, 0xB2, 0x43, 0xE1, + 0x85, 0xB3, 0x43, 0xE1, 0x85, 0xB4, 0x43, 0xE1, + 0x85, 0xB5, 0x43, 0xE1, 0x86, 0x84, 0x43, 0xE1, + 0x86, 0x85, 0x43, 0xE1, 0x86, 0x88, 0x43, 0xE1, + 0x86, 0x91, 0x43, 0xE1, 0x86, 0x92, 0x43, 0xE1, + 0x86, 0x94, 0x43, 0xE1, 0x86, 0x9E, 0x43, 0xE1, + 0x86, 0xA1, 0x43, 0xE1, 0x86, 0xAA, 0x43, 0xE1, + 0x86, 0xAC, 0x43, 0xE1, 0x86, 0xAD, 0x43, 0xE1, + // Bytes 440 - 47f + 0x86, 0xB0, 0x43, 0xE1, 0x86, 0xB1, 0x43, 0xE1, + 0x86, 0xB2, 0x43, 0xE1, 0x86, 0xB3, 0x43, 0xE1, + 0x86, 0xB4, 0x43, 0xE1, 0x86, 0xB5, 0x43, 0xE1, + 0x87, 0x87, 0x43, 0xE1, 0x87, 0x88, 0x43, 0xE1, + 0x87, 0x8C, 0x43, 0xE1, 0x87, 0x8E, 0x43, 0xE1, + 0x87, 0x93, 0x43, 0xE1, 0x87, 0x97, 0x43, 0xE1, + 0x87, 0x99, 0x43, 0xE1, 0x87, 0x9D, 0x43, 0xE1, + 0x87, 0x9F, 0x43, 0xE1, 0x87, 0xB1, 0x43, 0xE1, + // Bytes 480 - 4bf + 0x87, 0xB2, 0x43, 0xE1, 0xB4, 0x82, 0x43, 0xE1, + 0xB4, 0x96, 0x43, 0xE1, 0xB4, 0x97, 0x43, 0xE1, + 0xB4, 0x9C, 0x43, 0xE1, 0xB4, 0x9D, 0x43, 0xE1, + 0xB4, 0xA5, 0x43, 0xE1, 0xB5, 0xBB, 0x43, 0xE1, + 0xB6, 0x85, 0x43, 0xE2, 0x80, 0x82, 0x43, 0xE2, + 0x80, 0x83, 0x43, 0xE2, 0x80, 0x90, 0x43, 0xE2, + 0x80, 0x93, 0x43, 0xE2, 0x80, 0x94, 0x43, 0xE2, + 0x82, 0xA9, 0x43, 0xE2, 0x86, 0x90, 0x43, 0xE2, + // Bytes 4c0 - 4ff + 0x86, 0x91, 0x43, 0xE2, 0x86, 0x92, 0x43, 0xE2, + 0x86, 0x93, 0x43, 0xE2, 0x88, 0x82, 0x43, 0xE2, + 0x88, 0x87, 0x43, 0xE2, 0x88, 0x91, 0x43, 0xE2, + 0x88, 0x92, 0x43, 0xE2, 0x94, 0x82, 0x43, 0xE2, + 0x96, 0xA0, 0x43, 0xE2, 0x97, 0x8B, 0x43, 0xE2, + 0xA6, 0x85, 0x43, 0xE2, 0xA6, 0x86, 0x43, 0xE2, + 0xB5, 0xA1, 0x43, 0xE3, 0x80, 0x81, 0x43, 0xE3, + 0x80, 0x82, 0x43, 0xE3, 0x80, 0x88, 0x43, 0xE3, + // Bytes 500 - 53f + 0x80, 0x89, 0x43, 0xE3, 0x80, 0x8A, 0x43, 0xE3, + 0x80, 0x8B, 0x43, 0xE3, 0x80, 0x8C, 0x43, 0xE3, + 0x80, 0x8D, 0x43, 0xE3, 0x80, 0x8E, 0x43, 0xE3, + 0x80, 0x8F, 0x43, 0xE3, 0x80, 0x90, 0x43, 0xE3, + 0x80, 0x91, 0x43, 0xE3, 0x80, 0x92, 0x43, 0xE3, + 0x80, 0x94, 0x43, 0xE3, 0x80, 0x95, 0x43, 0xE3, + 0x80, 0x96, 0x43, 0xE3, 0x80, 0x97, 0x43, 0xE3, + 0x82, 0xA1, 0x43, 0xE3, 0x82, 0xA2, 0x43, 0xE3, + // Bytes 540 - 57f + 0x82, 0xA3, 0x43, 0xE3, 0x82, 0xA4, 0x43, 0xE3, + 0x82, 0xA5, 0x43, 0xE3, 0x82, 0xA6, 0x43, 0xE3, + 0x82, 0xA7, 0x43, 0xE3, 0x82, 0xA8, 0x43, 0xE3, + 0x82, 0xA9, 0x43, 0xE3, 0x82, 0xAA, 0x43, 0xE3, + 0x82, 0xAB, 0x43, 0xE3, 0x82, 0xAD, 0x43, 0xE3, + 0x82, 0xAF, 0x43, 0xE3, 0x82, 0xB1, 0x43, 0xE3, + 0x82, 0xB3, 0x43, 0xE3, 0x82, 0xB5, 0x43, 0xE3, + 0x82, 0xB7, 0x43, 0xE3, 0x82, 0xB9, 0x43, 0xE3, + // Bytes 580 - 5bf + 0x82, 0xBB, 0x43, 0xE3, 0x82, 0xBD, 0x43, 0xE3, + 0x82, 0xBF, 0x43, 0xE3, 0x83, 0x81, 0x43, 0xE3, + 0x83, 0x83, 0x43, 0xE3, 0x83, 0x84, 0x43, 0xE3, + 0x83, 0x86, 0x43, 0xE3, 0x83, 0x88, 0x43, 0xE3, + 0x83, 0x8A, 0x43, 0xE3, 0x83, 0x8B, 0x43, 0xE3, + 0x83, 0x8C, 0x43, 0xE3, 0x83, 0x8D, 0x43, 0xE3, + 0x83, 0x8E, 0x43, 0xE3, 0x83, 0x8F, 0x43, 0xE3, + 0x83, 0x92, 0x43, 0xE3, 0x83, 0x95, 0x43, 0xE3, + // Bytes 5c0 - 5ff + 0x83, 0x98, 0x43, 0xE3, 0x83, 0x9B, 0x43, 0xE3, + 0x83, 0x9E, 0x43, 0xE3, 0x83, 0x9F, 0x43, 0xE3, + 0x83, 0xA0, 0x43, 0xE3, 0x83, 0xA1, 0x43, 0xE3, + 0x83, 0xA2, 0x43, 0xE3, 0x83, 0xA3, 0x43, 0xE3, + 0x83, 0xA4, 0x43, 0xE3, 0x83, 0xA5, 0x43, 0xE3, + 0x83, 0xA6, 0x43, 0xE3, 0x83, 0xA7, 0x43, 0xE3, + 0x83, 0xA8, 0x43, 0xE3, 0x83, 0xA9, 0x43, 0xE3, + 0x83, 0xAA, 0x43, 0xE3, 0x83, 0xAB, 0x43, 0xE3, + // Bytes 600 - 63f + 0x83, 0xAC, 0x43, 0xE3, 0x83, 0xAD, 0x43, 0xE3, + 0x83, 0xAF, 0x43, 0xE3, 0x83, 0xB0, 0x43, 0xE3, + 0x83, 0xB1, 0x43, 0xE3, 0x83, 0xB2, 0x43, 0xE3, + 0x83, 0xB3, 0x43, 0xE3, 0x83, 0xBB, 0x43, 0xE3, + 0x83, 0xBC, 0x43, 0xE3, 0x92, 0x9E, 0x43, 0xE3, + 0x92, 0xB9, 0x43, 0xE3, 0x92, 0xBB, 0x43, 0xE3, + 0x93, 0x9F, 0x43, 0xE3, 0x94, 0x95, 0x43, 0xE3, + 0x9B, 0xAE, 0x43, 0xE3, 0x9B, 0xBC, 0x43, 0xE3, + // Bytes 640 - 67f + 0x9E, 0x81, 0x43, 0xE3, 0xA0, 0xAF, 0x43, 0xE3, + 0xA1, 0xA2, 0x43, 0xE3, 0xA1, 0xBC, 0x43, 0xE3, + 0xA3, 0x87, 0x43, 0xE3, 0xA3, 0xA3, 0x43, 0xE3, + 0xA4, 0x9C, 0x43, 0xE3, 0xA4, 0xBA, 0x43, 0xE3, + 0xA8, 0xAE, 0x43, 0xE3, 0xA9, 0xAC, 0x43, 0xE3, + 0xAB, 0xA4, 0x43, 0xE3, 0xAC, 0x88, 0x43, 0xE3, + 0xAC, 0x99, 0x43, 0xE3, 0xAD, 0x89, 0x43, 0xE3, + 0xAE, 0x9D, 0x43, 0xE3, 0xB0, 0x98, 0x43, 0xE3, + // Bytes 680 - 6bf + 0xB1, 0x8E, 0x43, 0xE3, 0xB4, 0xB3, 0x43, 0xE3, + 0xB6, 0x96, 0x43, 0xE3, 0xBA, 0xAC, 0x43, 0xE3, + 0xBA, 0xB8, 0x43, 0xE3, 0xBC, 0x9B, 0x43, 0xE3, + 0xBF, 0xBC, 0x43, 0xE4, 0x80, 0x88, 0x43, 0xE4, + 0x80, 0x98, 0x43, 0xE4, 0x80, 0xB9, 0x43, 0xE4, + 0x81, 0x86, 0x43, 0xE4, 0x82, 0x96, 0x43, 0xE4, + 0x83, 0xA3, 0x43, 0xE4, 0x84, 0xAF, 0x43, 0xE4, + 0x88, 0x82, 0x43, 0xE4, 0x88, 0xA7, 0x43, 0xE4, + // Bytes 6c0 - 6ff + 0x8A, 0xA0, 0x43, 0xE4, 0x8C, 0x81, 0x43, 0xE4, + 0x8C, 0xB4, 0x43, 0xE4, 0x8D, 0x99, 0x43, 0xE4, + 0x8F, 0x95, 0x43, 0xE4, 0x8F, 0x99, 0x43, 0xE4, + 0x90, 0x8B, 0x43, 0xE4, 0x91, 0xAB, 0x43, 0xE4, + 0x94, 0xAB, 0x43, 0xE4, 0x95, 0x9D, 0x43, 0xE4, + 0x95, 0xA1, 0x43, 0xE4, 0x95, 0xAB, 0x43, 0xE4, + 0x97, 0x97, 0x43, 0xE4, 0x97, 0xB9, 0x43, 0xE4, + 0x98, 0xB5, 0x43, 0xE4, 0x9A, 0xBE, 0x43, 0xE4, + // Bytes 700 - 73f + 0x9B, 0x87, 0x43, 0xE4, 0xA6, 0x95, 0x43, 0xE4, + 0xA7, 0xA6, 0x43, 0xE4, 0xA9, 0xAE, 0x43, 0xE4, + 0xA9, 0xB6, 0x43, 0xE4, 0xAA, 0xB2, 0x43, 0xE4, + 0xAC, 0xB3, 0x43, 0xE4, 0xAF, 0x8E, 0x43, 0xE4, + 0xB3, 0x8E, 0x43, 0xE4, 0xB3, 0xAD, 0x43, 0xE4, + 0xB3, 0xB8, 0x43, 0xE4, 0xB5, 0x96, 0x43, 0xE4, + 0xB8, 0x80, 0x43, 0xE4, 0xB8, 0x81, 0x43, 0xE4, + 0xB8, 0x83, 0x43, 0xE4, 0xB8, 0x89, 0x43, 0xE4, + // Bytes 740 - 77f + 0xB8, 0x8A, 0x43, 0xE4, 0xB8, 0x8B, 0x43, 0xE4, + 0xB8, 0x8D, 0x43, 0xE4, 0xB8, 0x99, 0x43, 0xE4, + 0xB8, 0xA6, 0x43, 0xE4, 0xB8, 0xA8, 0x43, 0xE4, + 0xB8, 0xAD, 0x43, 0xE4, 0xB8, 0xB2, 0x43, 0xE4, + 0xB8, 0xB6, 0x43, 0xE4, 0xB8, 0xB8, 0x43, 0xE4, + 0xB8, 0xB9, 0x43, 0xE4, 0xB8, 0xBD, 0x43, 0xE4, + 0xB8, 0xBF, 0x43, 0xE4, 0xB9, 0x81, 0x43, 0xE4, + 0xB9, 0x99, 0x43, 0xE4, 0xB9, 0x9D, 0x43, 0xE4, + // Bytes 780 - 7bf + 0xBA, 0x82, 0x43, 0xE4, 0xBA, 0x85, 0x43, 0xE4, + 0xBA, 0x86, 0x43, 0xE4, 0xBA, 0x8C, 0x43, 0xE4, + 0xBA, 0x94, 0x43, 0xE4, 0xBA, 0xA0, 0x43, 0xE4, + 0xBA, 0xA4, 0x43, 0xE4, 0xBA, 0xAE, 0x43, 0xE4, + 0xBA, 0xBA, 0x43, 0xE4, 0xBB, 0x80, 0x43, 0xE4, + 0xBB, 0x8C, 0x43, 0xE4, 0xBB, 0xA4, 0x43, 0xE4, + 0xBC, 0x81, 0x43, 0xE4, 0xBC, 0x91, 0x43, 0xE4, + 0xBD, 0xA0, 0x43, 0xE4, 0xBE, 0x80, 0x43, 0xE4, + // Bytes 7c0 - 7ff + 0xBE, 0x86, 0x43, 0xE4, 0xBE, 0x8B, 0x43, 0xE4, + 0xBE, 0xAE, 0x43, 0xE4, 0xBE, 0xBB, 0x43, 0xE4, + 0xBE, 0xBF, 0x43, 0xE5, 0x80, 0x82, 0x43, 0xE5, + 0x80, 0xAB, 0x43, 0xE5, 0x81, 0xBA, 0x43, 0xE5, + 0x82, 0x99, 0x43, 0xE5, 0x83, 0x8F, 0x43, 0xE5, + 0x83, 0x9A, 0x43, 0xE5, 0x83, 0xA7, 0x43, 0xE5, + 0x84, 0xAA, 0x43, 0xE5, 0x84, 0xBF, 0x43, 0xE5, + 0x85, 0x80, 0x43, 0xE5, 0x85, 0x85, 0x43, 0xE5, + // Bytes 800 - 83f + 0x85, 0x8D, 0x43, 0xE5, 0x85, 0x94, 0x43, 0xE5, + 0x85, 0xA4, 0x43, 0xE5, 0x85, 0xA5, 0x43, 0xE5, + 0x85, 0xA7, 0x43, 0xE5, 0x85, 0xA8, 0x43, 0xE5, + 0x85, 0xA9, 0x43, 0xE5, 0x85, 0xAB, 0x43, 0xE5, + 0x85, 0xAD, 0x43, 0xE5, 0x85, 0xB7, 0x43, 0xE5, + 0x86, 0x80, 0x43, 0xE5, 0x86, 0x82, 0x43, 0xE5, + 0x86, 0x8D, 0x43, 0xE5, 0x86, 0x92, 0x43, 0xE5, + 0x86, 0x95, 0x43, 0xE5, 0x86, 0x96, 0x43, 0xE5, + // Bytes 840 - 87f + 0x86, 0x97, 0x43, 0xE5, 0x86, 0x99, 0x43, 0xE5, + 0x86, 0xA4, 0x43, 0xE5, 0x86, 0xAB, 0x43, 0xE5, + 0x86, 0xAC, 0x43, 0xE5, 0x86, 0xB5, 0x43, 0xE5, + 0x86, 0xB7, 0x43, 0xE5, 0x87, 0x89, 0x43, 0xE5, + 0x87, 0x8C, 0x43, 0xE5, 0x87, 0x9C, 0x43, 0xE5, + 0x87, 0x9E, 0x43, 0xE5, 0x87, 0xA0, 0x43, 0xE5, + 0x87, 0xB5, 0x43, 0xE5, 0x88, 0x80, 0x43, 0xE5, + 0x88, 0x83, 0x43, 0xE5, 0x88, 0x87, 0x43, 0xE5, + // Bytes 880 - 8bf + 0x88, 0x97, 0x43, 0xE5, 0x88, 0x9D, 0x43, 0xE5, + 0x88, 0xA9, 0x43, 0xE5, 0x88, 0xBA, 0x43, 0xE5, + 0x88, 0xBB, 0x43, 0xE5, 0x89, 0x86, 0x43, 0xE5, + 0x89, 0x8D, 0x43, 0xE5, 0x89, 0xB2, 0x43, 0xE5, + 0x89, 0xB7, 0x43, 0xE5, 0x8A, 0x89, 0x43, 0xE5, + 0x8A, 0x9B, 0x43, 0xE5, 0x8A, 0xA3, 0x43, 0xE5, + 0x8A, 0xB3, 0x43, 0xE5, 0x8A, 0xB4, 0x43, 0xE5, + 0x8B, 0x87, 0x43, 0xE5, 0x8B, 0x89, 0x43, 0xE5, + // Bytes 8c0 - 8ff + 0x8B, 0x92, 0x43, 0xE5, 0x8B, 0x9E, 0x43, 0xE5, + 0x8B, 0xA4, 0x43, 0xE5, 0x8B, 0xB5, 0x43, 0xE5, + 0x8B, 0xB9, 0x43, 0xE5, 0x8B, 0xBA, 0x43, 0xE5, + 0x8C, 0x85, 0x43, 0xE5, 0x8C, 0x86, 0x43, 0xE5, + 0x8C, 0x95, 0x43, 0xE5, 0x8C, 0x97, 0x43, 0xE5, + 0x8C, 0x9A, 0x43, 0xE5, 0x8C, 0xB8, 0x43, 0xE5, + 0x8C, 0xBB, 0x43, 0xE5, 0x8C, 0xBF, 0x43, 0xE5, + 0x8D, 0x81, 0x43, 0xE5, 0x8D, 0x84, 0x43, 0xE5, + // Bytes 900 - 93f + 0x8D, 0x85, 0x43, 0xE5, 0x8D, 0x89, 0x43, 0xE5, + 0x8D, 0x91, 0x43, 0xE5, 0x8D, 0x94, 0x43, 0xE5, + 0x8D, 0x9A, 0x43, 0xE5, 0x8D, 0x9C, 0x43, 0xE5, + 0x8D, 0xA9, 0x43, 0xE5, 0x8D, 0xB0, 0x43, 0xE5, + 0x8D, 0xB3, 0x43, 0xE5, 0x8D, 0xB5, 0x43, 0xE5, + 0x8D, 0xBD, 0x43, 0xE5, 0x8D, 0xBF, 0x43, 0xE5, + 0x8E, 0x82, 0x43, 0xE5, 0x8E, 0xB6, 0x43, 0xE5, + 0x8F, 0x83, 0x43, 0xE5, 0x8F, 0x88, 0x43, 0xE5, + // Bytes 940 - 97f + 0x8F, 0x8A, 0x43, 0xE5, 0x8F, 0x8C, 0x43, 0xE5, + 0x8F, 0x9F, 0x43, 0xE5, 0x8F, 0xA3, 0x43, 0xE5, + 0x8F, 0xA5, 0x43, 0xE5, 0x8F, 0xAB, 0x43, 0xE5, + 0x8F, 0xAF, 0x43, 0xE5, 0x8F, 0xB1, 0x43, 0xE5, + 0x8F, 0xB3, 0x43, 0xE5, 0x90, 0x86, 0x43, 0xE5, + 0x90, 0x88, 0x43, 0xE5, 0x90, 0x8D, 0x43, 0xE5, + 0x90, 0x8F, 0x43, 0xE5, 0x90, 0x9D, 0x43, 0xE5, + 0x90, 0xB8, 0x43, 0xE5, 0x90, 0xB9, 0x43, 0xE5, + // Bytes 980 - 9bf + 0x91, 0x82, 0x43, 0xE5, 0x91, 0x88, 0x43, 0xE5, + 0x91, 0xA8, 0x43, 0xE5, 0x92, 0x9E, 0x43, 0xE5, + 0x92, 0xA2, 0x43, 0xE5, 0x92, 0xBD, 0x43, 0xE5, + 0x93, 0xB6, 0x43, 0xE5, 0x94, 0x90, 0x43, 0xE5, + 0x95, 0x8F, 0x43, 0xE5, 0x95, 0x93, 0x43, 0xE5, + 0x95, 0x95, 0x43, 0xE5, 0x95, 0xA3, 0x43, 0xE5, + 0x96, 0x84, 0x43, 0xE5, 0x96, 0x87, 0x43, 0xE5, + 0x96, 0x99, 0x43, 0xE5, 0x96, 0x9D, 0x43, 0xE5, + // Bytes 9c0 - 9ff + 0x96, 0xAB, 0x43, 0xE5, 0x96, 0xB3, 0x43, 0xE5, + 0x96, 0xB6, 0x43, 0xE5, 0x97, 0x80, 0x43, 0xE5, + 0x97, 0x82, 0x43, 0xE5, 0x97, 0xA2, 0x43, 0xE5, + 0x98, 0x86, 0x43, 0xE5, 0x99, 0x91, 0x43, 0xE5, + 0x99, 0xA8, 0x43, 0xE5, 0x99, 0xB4, 0x43, 0xE5, + 0x9B, 0x97, 0x43, 0xE5, 0x9B, 0x9B, 0x43, 0xE5, + 0x9B, 0xB9, 0x43, 0xE5, 0x9C, 0x96, 0x43, 0xE5, + 0x9C, 0x97, 0x43, 0xE5, 0x9C, 0x9F, 0x43, 0xE5, + // Bytes a00 - a3f + 0x9C, 0xB0, 0x43, 0xE5, 0x9E, 0x8B, 0x43, 0xE5, + 0x9F, 0x8E, 0x43, 0xE5, 0x9F, 0xB4, 0x43, 0xE5, + 0xA0, 0x8D, 0x43, 0xE5, 0xA0, 0xB1, 0x43, 0xE5, + 0xA0, 0xB2, 0x43, 0xE5, 0xA1, 0x80, 0x43, 0xE5, + 0xA1, 0x9A, 0x43, 0xE5, 0xA1, 0x9E, 0x43, 0xE5, + 0xA2, 0xA8, 0x43, 0xE5, 0xA2, 0xAC, 0x43, 0xE5, + 0xA2, 0xB3, 0x43, 0xE5, 0xA3, 0x98, 0x43, 0xE5, + 0xA3, 0x9F, 0x43, 0xE5, 0xA3, 0xAB, 0x43, 0xE5, + // Bytes a40 - a7f + 0xA3, 0xAE, 0x43, 0xE5, 0xA3, 0xB0, 0x43, 0xE5, + 0xA3, 0xB2, 0x43, 0xE5, 0xA3, 0xB7, 0x43, 0xE5, + 0xA4, 0x82, 0x43, 0xE5, 0xA4, 0x86, 0x43, 0xE5, + 0xA4, 0x8A, 0x43, 0xE5, 0xA4, 0x95, 0x43, 0xE5, + 0xA4, 0x9A, 0x43, 0xE5, 0xA4, 0x9C, 0x43, 0xE5, + 0xA4, 0xA2, 0x43, 0xE5, 0xA4, 0xA7, 0x43, 0xE5, + 0xA4, 0xA9, 0x43, 0xE5, 0xA5, 0x84, 0x43, 0xE5, + 0xA5, 0x88, 0x43, 0xE5, 0xA5, 0x91, 0x43, 0xE5, + // Bytes a80 - abf + 0xA5, 0x94, 0x43, 0xE5, 0xA5, 0xA2, 0x43, 0xE5, + 0xA5, 0xB3, 0x43, 0xE5, 0xA7, 0x98, 0x43, 0xE5, + 0xA7, 0xAC, 0x43, 0xE5, 0xA8, 0x9B, 0x43, 0xE5, + 0xA8, 0xA7, 0x43, 0xE5, 0xA9, 0xA2, 0x43, 0xE5, + 0xA9, 0xA6, 0x43, 0xE5, 0xAA, 0xB5, 0x43, 0xE5, + 0xAC, 0x88, 0x43, 0xE5, 0xAC, 0xA8, 0x43, 0xE5, + 0xAC, 0xBE, 0x43, 0xE5, 0xAD, 0x90, 0x43, 0xE5, + 0xAD, 0x97, 0x43, 0xE5, 0xAD, 0xA6, 0x43, 0xE5, + // Bytes ac0 - aff + 0xAE, 0x80, 0x43, 0xE5, 0xAE, 0x85, 0x43, 0xE5, + 0xAE, 0x97, 0x43, 0xE5, 0xAF, 0x83, 0x43, 0xE5, + 0xAF, 0x98, 0x43, 0xE5, 0xAF, 0xA7, 0x43, 0xE5, + 0xAF, 0xAE, 0x43, 0xE5, 0xAF, 0xB3, 0x43, 0xE5, + 0xAF, 0xB8, 0x43, 0xE5, 0xAF, 0xBF, 0x43, 0xE5, + 0xB0, 0x86, 0x43, 0xE5, 0xB0, 0x8F, 0x43, 0xE5, + 0xB0, 0xA2, 0x43, 0xE5, 0xB0, 0xB8, 0x43, 0xE5, + 0xB0, 0xBF, 0x43, 0xE5, 0xB1, 0xA0, 0x43, 0xE5, + // Bytes b00 - b3f + 0xB1, 0xA2, 0x43, 0xE5, 0xB1, 0xA4, 0x43, 0xE5, + 0xB1, 0xA5, 0x43, 0xE5, 0xB1, 0xAE, 0x43, 0xE5, + 0xB1, 0xB1, 0x43, 0xE5, 0xB2, 0x8D, 0x43, 0xE5, + 0xB3, 0x80, 0x43, 0xE5, 0xB4, 0x99, 0x43, 0xE5, + 0xB5, 0x83, 0x43, 0xE5, 0xB5, 0x90, 0x43, 0xE5, + 0xB5, 0xAB, 0x43, 0xE5, 0xB5, 0xAE, 0x43, 0xE5, + 0xB5, 0xBC, 0x43, 0xE5, 0xB6, 0xB2, 0x43, 0xE5, + 0xB6, 0xBA, 0x43, 0xE5, 0xB7, 0x9B, 0x43, 0xE5, + // Bytes b40 - b7f + 0xB7, 0xA1, 0x43, 0xE5, 0xB7, 0xA2, 0x43, 0xE5, + 0xB7, 0xA5, 0x43, 0xE5, 0xB7, 0xA6, 0x43, 0xE5, + 0xB7, 0xB1, 0x43, 0xE5, 0xB7, 0xBD, 0x43, 0xE5, + 0xB7, 0xBE, 0x43, 0xE5, 0xB8, 0xA8, 0x43, 0xE5, + 0xB8, 0xBD, 0x43, 0xE5, 0xB9, 0xA9, 0x43, 0xE5, + 0xB9, 0xB2, 0x43, 0xE5, 0xB9, 0xB4, 0x43, 0xE5, + 0xB9, 0xBA, 0x43, 0xE5, 0xB9, 0xBC, 0x43, 0xE5, + 0xB9, 0xBF, 0x43, 0xE5, 0xBA, 0xA6, 0x43, 0xE5, + // Bytes b80 - bbf + 0xBA, 0xB0, 0x43, 0xE5, 0xBA, 0xB3, 0x43, 0xE5, + 0xBA, 0xB6, 0x43, 0xE5, 0xBB, 0x89, 0x43, 0xE5, + 0xBB, 0x8A, 0x43, 0xE5, 0xBB, 0x92, 0x43, 0xE5, + 0xBB, 0x93, 0x43, 0xE5, 0xBB, 0x99, 0x43, 0xE5, + 0xBB, 0xAC, 0x43, 0xE5, 0xBB, 0xB4, 0x43, 0xE5, + 0xBB, 0xBE, 0x43, 0xE5, 0xBC, 0x84, 0x43, 0xE5, + 0xBC, 0x8B, 0x43, 0xE5, 0xBC, 0x93, 0x43, 0xE5, + 0xBC, 0xA2, 0x43, 0xE5, 0xBD, 0x90, 0x43, 0xE5, + // Bytes bc0 - bff + 0xBD, 0x93, 0x43, 0xE5, 0xBD, 0xA1, 0x43, 0xE5, + 0xBD, 0xA2, 0x43, 0xE5, 0xBD, 0xA9, 0x43, 0xE5, + 0xBD, 0xAB, 0x43, 0xE5, 0xBD, 0xB3, 0x43, 0xE5, + 0xBE, 0x8B, 0x43, 0xE5, 0xBE, 0x8C, 0x43, 0xE5, + 0xBE, 0x97, 0x43, 0xE5, 0xBE, 0x9A, 0x43, 0xE5, + 0xBE, 0xA9, 0x43, 0xE5, 0xBE, 0xAD, 0x43, 0xE5, + 0xBF, 0x83, 0x43, 0xE5, 0xBF, 0x8D, 0x43, 0xE5, + 0xBF, 0x97, 0x43, 0xE5, 0xBF, 0xB5, 0x43, 0xE5, + // Bytes c00 - c3f + 0xBF, 0xB9, 0x43, 0xE6, 0x80, 0x92, 0x43, 0xE6, + 0x80, 0x9C, 0x43, 0xE6, 0x81, 0xB5, 0x43, 0xE6, + 0x82, 0x81, 0x43, 0xE6, 0x82, 0x94, 0x43, 0xE6, + 0x83, 0x87, 0x43, 0xE6, 0x83, 0x98, 0x43, 0xE6, + 0x83, 0xA1, 0x43, 0xE6, 0x84, 0x88, 0x43, 0xE6, + 0x85, 0x84, 0x43, 0xE6, 0x85, 0x88, 0x43, 0xE6, + 0x85, 0x8C, 0x43, 0xE6, 0x85, 0x8E, 0x43, 0xE6, + 0x85, 0xA0, 0x43, 0xE6, 0x85, 0xA8, 0x43, 0xE6, + // Bytes c40 - c7f + 0x85, 0xBA, 0x43, 0xE6, 0x86, 0x8E, 0x43, 0xE6, + 0x86, 0x90, 0x43, 0xE6, 0x86, 0xA4, 0x43, 0xE6, + 0x86, 0xAF, 0x43, 0xE6, 0x86, 0xB2, 0x43, 0xE6, + 0x87, 0x9E, 0x43, 0xE6, 0x87, 0xB2, 0x43, 0xE6, + 0x87, 0xB6, 0x43, 0xE6, 0x88, 0x80, 0x43, 0xE6, + 0x88, 0x88, 0x43, 0xE6, 0x88, 0x90, 0x43, 0xE6, + 0x88, 0x9B, 0x43, 0xE6, 0x88, 0xAE, 0x43, 0xE6, + 0x88, 0xB4, 0x43, 0xE6, 0x88, 0xB6, 0x43, 0xE6, + // Bytes c80 - cbf + 0x89, 0x8B, 0x43, 0xE6, 0x89, 0x93, 0x43, 0xE6, + 0x89, 0x9D, 0x43, 0xE6, 0x8A, 0x95, 0x43, 0xE6, + 0x8A, 0xB1, 0x43, 0xE6, 0x8B, 0x89, 0x43, 0xE6, + 0x8B, 0x8F, 0x43, 0xE6, 0x8B, 0x93, 0x43, 0xE6, + 0x8B, 0x94, 0x43, 0xE6, 0x8B, 0xBC, 0x43, 0xE6, + 0x8B, 0xBE, 0x43, 0xE6, 0x8C, 0x87, 0x43, 0xE6, + 0x8C, 0xBD, 0x43, 0xE6, 0x8D, 0x90, 0x43, 0xE6, + 0x8D, 0x95, 0x43, 0xE6, 0x8D, 0xA8, 0x43, 0xE6, + // Bytes cc0 - cff + 0x8D, 0xBB, 0x43, 0xE6, 0x8E, 0x83, 0x43, 0xE6, + 0x8E, 0xA0, 0x43, 0xE6, 0x8E, 0xA9, 0x43, 0xE6, + 0x8F, 0x84, 0x43, 0xE6, 0x8F, 0x85, 0x43, 0xE6, + 0x8F, 0xA4, 0x43, 0xE6, 0x90, 0x9C, 0x43, 0xE6, + 0x90, 0xA2, 0x43, 0xE6, 0x91, 0x92, 0x43, 0xE6, + 0x91, 0xA9, 0x43, 0xE6, 0x91, 0xB7, 0x43, 0xE6, + 0x91, 0xBE, 0x43, 0xE6, 0x92, 0x9A, 0x43, 0xE6, + 0x92, 0x9D, 0x43, 0xE6, 0x93, 0x84, 0x43, 0xE6, + // Bytes d00 - d3f + 0x94, 0xAF, 0x43, 0xE6, 0x94, 0xB4, 0x43, 0xE6, + 0x95, 0x8F, 0x43, 0xE6, 0x95, 0x96, 0x43, 0xE6, + 0x95, 0xAC, 0x43, 0xE6, 0x95, 0xB8, 0x43, 0xE6, + 0x96, 0x87, 0x43, 0xE6, 0x96, 0x97, 0x43, 0xE6, + 0x96, 0x99, 0x43, 0xE6, 0x96, 0xA4, 0x43, 0xE6, + 0x96, 0xB0, 0x43, 0xE6, 0x96, 0xB9, 0x43, 0xE6, + 0x97, 0x85, 0x43, 0xE6, 0x97, 0xA0, 0x43, 0xE6, + 0x97, 0xA2, 0x43, 0xE6, 0x97, 0xA3, 0x43, 0xE6, + // Bytes d40 - d7f + 0x97, 0xA5, 0x43, 0xE6, 0x98, 0x93, 0x43, 0xE6, + 0x98, 0xA0, 0x43, 0xE6, 0x99, 0x89, 0x43, 0xE6, + 0x99, 0xB4, 0x43, 0xE6, 0x9A, 0x88, 0x43, 0xE6, + 0x9A, 0x91, 0x43, 0xE6, 0x9A, 0x9C, 0x43, 0xE6, + 0x9A, 0xB4, 0x43, 0xE6, 0x9B, 0x86, 0x43, 0xE6, + 0x9B, 0xB0, 0x43, 0xE6, 0x9B, 0xB4, 0x43, 0xE6, + 0x9B, 0xB8, 0x43, 0xE6, 0x9C, 0x80, 0x43, 0xE6, + 0x9C, 0x88, 0x43, 0xE6, 0x9C, 0x89, 0x43, 0xE6, + // Bytes d80 - dbf + 0x9C, 0x97, 0x43, 0xE6, 0x9C, 0x9B, 0x43, 0xE6, + 0x9C, 0xA1, 0x43, 0xE6, 0x9C, 0xA8, 0x43, 0xE6, + 0x9D, 0x8E, 0x43, 0xE6, 0x9D, 0x93, 0x43, 0xE6, + 0x9D, 0x96, 0x43, 0xE6, 0x9D, 0x9E, 0x43, 0xE6, + 0x9D, 0xBB, 0x43, 0xE6, 0x9E, 0x85, 0x43, 0xE6, + 0x9E, 0x97, 0x43, 0xE6, 0x9F, 0xB3, 0x43, 0xE6, + 0x9F, 0xBA, 0x43, 0xE6, 0xA0, 0x97, 0x43, 0xE6, + 0xA0, 0x9F, 0x43, 0xE6, 0xA0, 0xAA, 0x43, 0xE6, + // Bytes dc0 - dff + 0xA1, 0x92, 0x43, 0xE6, 0xA2, 0x81, 0x43, 0xE6, + 0xA2, 0x85, 0x43, 0xE6, 0xA2, 0x8E, 0x43, 0xE6, + 0xA2, 0xA8, 0x43, 0xE6, 0xA4, 0x94, 0x43, 0xE6, + 0xA5, 0x82, 0x43, 0xE6, 0xA6, 0xA3, 0x43, 0xE6, + 0xA7, 0xAA, 0x43, 0xE6, 0xA8, 0x82, 0x43, 0xE6, + 0xA8, 0x93, 0x43, 0xE6, 0xAA, 0xA8, 0x43, 0xE6, + 0xAB, 0x93, 0x43, 0xE6, 0xAB, 0x9B, 0x43, 0xE6, + 0xAC, 0x84, 0x43, 0xE6, 0xAC, 0xA0, 0x43, 0xE6, + // Bytes e00 - e3f + 0xAC, 0xA1, 0x43, 0xE6, 0xAD, 0x94, 0x43, 0xE6, + 0xAD, 0xA2, 0x43, 0xE6, 0xAD, 0xA3, 0x43, 0xE6, + 0xAD, 0xB2, 0x43, 0xE6, 0xAD, 0xB7, 0x43, 0xE6, + 0xAD, 0xB9, 0x43, 0xE6, 0xAE, 0x9F, 0x43, 0xE6, + 0xAE, 0xAE, 0x43, 0xE6, 0xAE, 0xB3, 0x43, 0xE6, + 0xAE, 0xBA, 0x43, 0xE6, 0xAE, 0xBB, 0x43, 0xE6, + 0xAF, 0x8B, 0x43, 0xE6, 0xAF, 0x8D, 0x43, 0xE6, + 0xAF, 0x94, 0x43, 0xE6, 0xAF, 0x9B, 0x43, 0xE6, + // Bytes e40 - e7f + 0xB0, 0x8F, 0x43, 0xE6, 0xB0, 0x94, 0x43, 0xE6, + 0xB0, 0xB4, 0x43, 0xE6, 0xB1, 0x8E, 0x43, 0xE6, + 0xB1, 0xA7, 0x43, 0xE6, 0xB2, 0x88, 0x43, 0xE6, + 0xB2, 0xBF, 0x43, 0xE6, 0xB3, 0x8C, 0x43, 0xE6, + 0xB3, 0x8D, 0x43, 0xE6, 0xB3, 0xA5, 0x43, 0xE6, + 0xB3, 0xA8, 0x43, 0xE6, 0xB4, 0x96, 0x43, 0xE6, + 0xB4, 0x9B, 0x43, 0xE6, 0xB4, 0x9E, 0x43, 0xE6, + 0xB4, 0xB4, 0x43, 0xE6, 0xB4, 0xBE, 0x43, 0xE6, + // Bytes e80 - ebf + 0xB5, 0x81, 0x43, 0xE6, 0xB5, 0xA9, 0x43, 0xE6, + 0xB5, 0xAA, 0x43, 0xE6, 0xB5, 0xB7, 0x43, 0xE6, + 0xB5, 0xB8, 0x43, 0xE6, 0xB6, 0x85, 0x43, 0xE6, + 0xB7, 0x8B, 0x43, 0xE6, 0xB7, 0x9A, 0x43, 0xE6, + 0xB7, 0xAA, 0x43, 0xE6, 0xB7, 0xB9, 0x43, 0xE6, + 0xB8, 0x9A, 0x43, 0xE6, 0xB8, 0xAF, 0x43, 0xE6, + 0xB9, 0xAE, 0x43, 0xE6, 0xBA, 0x80, 0x43, 0xE6, + 0xBA, 0x9C, 0x43, 0xE6, 0xBA, 0xBA, 0x43, 0xE6, + // Bytes ec0 - eff + 0xBB, 0x87, 0x43, 0xE6, 0xBB, 0x8B, 0x43, 0xE6, + 0xBB, 0x91, 0x43, 0xE6, 0xBB, 0x9B, 0x43, 0xE6, + 0xBC, 0x8F, 0x43, 0xE6, 0xBC, 0x94, 0x43, 0xE6, + 0xBC, 0xA2, 0x43, 0xE6, 0xBC, 0xA3, 0x43, 0xE6, + 0xBD, 0xAE, 0x43, 0xE6, 0xBF, 0x86, 0x43, 0xE6, + 0xBF, 0xAB, 0x43, 0xE6, 0xBF, 0xBE, 0x43, 0xE7, + 0x80, 0x9B, 0x43, 0xE7, 0x80, 0x9E, 0x43, 0xE7, + 0x80, 0xB9, 0x43, 0xE7, 0x81, 0x8A, 0x43, 0xE7, + // Bytes f00 - f3f + 0x81, 0xAB, 0x43, 0xE7, 0x81, 0xB0, 0x43, 0xE7, + 0x81, 0xB7, 0x43, 0xE7, 0x81, 0xBD, 0x43, 0xE7, + 0x82, 0x99, 0x43, 0xE7, 0x82, 0xAD, 0x43, 0xE7, + 0x83, 0x88, 0x43, 0xE7, 0x83, 0x99, 0x43, 0xE7, + 0x84, 0xA1, 0x43, 0xE7, 0x85, 0x85, 0x43, 0xE7, + 0x85, 0x89, 0x43, 0xE7, 0x85, 0xAE, 0x43, 0xE7, + 0x86, 0x9C, 0x43, 0xE7, 0x87, 0x8E, 0x43, 0xE7, + 0x87, 0x90, 0x43, 0xE7, 0x88, 0x90, 0x43, 0xE7, + // Bytes f40 - f7f + 0x88, 0x9B, 0x43, 0xE7, 0x88, 0xA8, 0x43, 0xE7, + 0x88, 0xAA, 0x43, 0xE7, 0x88, 0xAB, 0x43, 0xE7, + 0x88, 0xB5, 0x43, 0xE7, 0x88, 0xB6, 0x43, 0xE7, + 0x88, 0xBB, 0x43, 0xE7, 0x88, 0xBF, 0x43, 0xE7, + 0x89, 0x87, 0x43, 0xE7, 0x89, 0x90, 0x43, 0xE7, + 0x89, 0x99, 0x43, 0xE7, 0x89, 0x9B, 0x43, 0xE7, + 0x89, 0xA2, 0x43, 0xE7, 0x89, 0xB9, 0x43, 0xE7, + 0x8A, 0x80, 0x43, 0xE7, 0x8A, 0x95, 0x43, 0xE7, + // Bytes f80 - fbf + 0x8A, 0xAC, 0x43, 0xE7, 0x8A, 0xAF, 0x43, 0xE7, + 0x8B, 0x80, 0x43, 0xE7, 0x8B, 0xBC, 0x43, 0xE7, + 0x8C, 0xAA, 0x43, 0xE7, 0x8D, 0xB5, 0x43, 0xE7, + 0x8D, 0xBA, 0x43, 0xE7, 0x8E, 0x84, 0x43, 0xE7, + 0x8E, 0x87, 0x43, 0xE7, 0x8E, 0x89, 0x43, 0xE7, + 0x8E, 0x8B, 0x43, 0xE7, 0x8E, 0xA5, 0x43, 0xE7, + 0x8E, 0xB2, 0x43, 0xE7, 0x8F, 0x9E, 0x43, 0xE7, + 0x90, 0x86, 0x43, 0xE7, 0x90, 0x89, 0x43, 0xE7, + // Bytes fc0 - fff + 0x90, 0xA2, 0x43, 0xE7, 0x91, 0x87, 0x43, 0xE7, + 0x91, 0x9C, 0x43, 0xE7, 0x91, 0xA9, 0x43, 0xE7, + 0x91, 0xB1, 0x43, 0xE7, 0x92, 0x85, 0x43, 0xE7, + 0x92, 0x89, 0x43, 0xE7, 0x92, 0x98, 0x43, 0xE7, + 0x93, 0x8A, 0x43, 0xE7, 0x93, 0x9C, 0x43, 0xE7, + 0x93, 0xA6, 0x43, 0xE7, 0x94, 0x86, 0x43, 0xE7, + 0x94, 0x98, 0x43, 0xE7, 0x94, 0x9F, 0x43, 0xE7, + 0x94, 0xA4, 0x43, 0xE7, 0x94, 0xA8, 0x43, 0xE7, + // Bytes 1000 - 103f + 0x94, 0xB0, 0x43, 0xE7, 0x94, 0xB2, 0x43, 0xE7, + 0x94, 0xB3, 0x43, 0xE7, 0x94, 0xB7, 0x43, 0xE7, + 0x94, 0xBB, 0x43, 0xE7, 0x94, 0xBE, 0x43, 0xE7, + 0x95, 0x99, 0x43, 0xE7, 0x95, 0xA5, 0x43, 0xE7, + 0x95, 0xB0, 0x43, 0xE7, 0x96, 0x8B, 0x43, 0xE7, + 0x96, 0x92, 0x43, 0xE7, 0x97, 0xA2, 0x43, 0xE7, + 0x98, 0x90, 0x43, 0xE7, 0x98, 0x9D, 0x43, 0xE7, + 0x98, 0x9F, 0x43, 0xE7, 0x99, 0x82, 0x43, 0xE7, + // Bytes 1040 - 107f + 0x99, 0xA9, 0x43, 0xE7, 0x99, 0xB6, 0x43, 0xE7, + 0x99, 0xBD, 0x43, 0xE7, 0x9A, 0xAE, 0x43, 0xE7, + 0x9A, 0xBF, 0x43, 0xE7, 0x9B, 0x8A, 0x43, 0xE7, + 0x9B, 0x9B, 0x43, 0xE7, 0x9B, 0xA3, 0x43, 0xE7, + 0x9B, 0xA7, 0x43, 0xE7, 0x9B, 0xAE, 0x43, 0xE7, + 0x9B, 0xB4, 0x43, 0xE7, 0x9C, 0x81, 0x43, 0xE7, + 0x9C, 0x9E, 0x43, 0xE7, 0x9C, 0x9F, 0x43, 0xE7, + 0x9D, 0x80, 0x43, 0xE7, 0x9D, 0x8A, 0x43, 0xE7, + // Bytes 1080 - 10bf + 0x9E, 0x8B, 0x43, 0xE7, 0x9E, 0xA7, 0x43, 0xE7, + 0x9F, 0x9B, 0x43, 0xE7, 0x9F, 0xA2, 0x43, 0xE7, + 0x9F, 0xB3, 0x43, 0xE7, 0xA1, 0x8E, 0x43, 0xE7, + 0xA1, 0xAB, 0x43, 0xE7, 0xA2, 0x8C, 0x43, 0xE7, + 0xA2, 0x91, 0x43, 0xE7, 0xA3, 0x8A, 0x43, 0xE7, + 0xA3, 0x8C, 0x43, 0xE7, 0xA3, 0xBB, 0x43, 0xE7, + 0xA4, 0xAA, 0x43, 0xE7, 0xA4, 0xBA, 0x43, 0xE7, + 0xA4, 0xBC, 0x43, 0xE7, 0xA4, 0xBE, 0x43, 0xE7, + // Bytes 10c0 - 10ff + 0xA5, 0x88, 0x43, 0xE7, 0xA5, 0x89, 0x43, 0xE7, + 0xA5, 0x90, 0x43, 0xE7, 0xA5, 0x96, 0x43, 0xE7, + 0xA5, 0x9D, 0x43, 0xE7, 0xA5, 0x9E, 0x43, 0xE7, + 0xA5, 0xA5, 0x43, 0xE7, 0xA5, 0xBF, 0x43, 0xE7, + 0xA6, 0x81, 0x43, 0xE7, 0xA6, 0x8D, 0x43, 0xE7, + 0xA6, 0x8E, 0x43, 0xE7, 0xA6, 0x8F, 0x43, 0xE7, + 0xA6, 0xAE, 0x43, 0xE7, 0xA6, 0xB8, 0x43, 0xE7, + 0xA6, 0xBE, 0x43, 0xE7, 0xA7, 0x8A, 0x43, 0xE7, + // Bytes 1100 - 113f + 0xA7, 0x98, 0x43, 0xE7, 0xA7, 0xAB, 0x43, 0xE7, + 0xA8, 0x9C, 0x43, 0xE7, 0xA9, 0x80, 0x43, 0xE7, + 0xA9, 0x8A, 0x43, 0xE7, 0xA9, 0x8F, 0x43, 0xE7, + 0xA9, 0xB4, 0x43, 0xE7, 0xA9, 0xBA, 0x43, 0xE7, + 0xAA, 0x81, 0x43, 0xE7, 0xAA, 0xB1, 0x43, 0xE7, + 0xAB, 0x8B, 0x43, 0xE7, 0xAB, 0xAE, 0x43, 0xE7, + 0xAB, 0xB9, 0x43, 0xE7, 0xAC, 0xA0, 0x43, 0xE7, + 0xAE, 0x8F, 0x43, 0xE7, 0xAF, 0x80, 0x43, 0xE7, + // Bytes 1140 - 117f + 0xAF, 0x86, 0x43, 0xE7, 0xAF, 0x89, 0x43, 0xE7, + 0xB0, 0xBE, 0x43, 0xE7, 0xB1, 0xA0, 0x43, 0xE7, + 0xB1, 0xB3, 0x43, 0xE7, 0xB1, 0xBB, 0x43, 0xE7, + 0xB2, 0x92, 0x43, 0xE7, 0xB2, 0xBE, 0x43, 0xE7, + 0xB3, 0x92, 0x43, 0xE7, 0xB3, 0x96, 0x43, 0xE7, + 0xB3, 0xA3, 0x43, 0xE7, 0xB3, 0xA7, 0x43, 0xE7, + 0xB3, 0xA8, 0x43, 0xE7, 0xB3, 0xB8, 0x43, 0xE7, + 0xB4, 0x80, 0x43, 0xE7, 0xB4, 0x90, 0x43, 0xE7, + // Bytes 1180 - 11bf + 0xB4, 0xA2, 0x43, 0xE7, 0xB4, 0xAF, 0x43, 0xE7, + 0xB5, 0x82, 0x43, 0xE7, 0xB5, 0x9B, 0x43, 0xE7, + 0xB5, 0xA3, 0x43, 0xE7, 0xB6, 0xA0, 0x43, 0xE7, + 0xB6, 0xBE, 0x43, 0xE7, 0xB7, 0x87, 0x43, 0xE7, + 0xB7, 0xB4, 0x43, 0xE7, 0xB8, 0x82, 0x43, 0xE7, + 0xB8, 0x89, 0x43, 0xE7, 0xB8, 0xB7, 0x43, 0xE7, + 0xB9, 0x81, 0x43, 0xE7, 0xB9, 0x85, 0x43, 0xE7, + 0xBC, 0xB6, 0x43, 0xE7, 0xBC, 0xBE, 0x43, 0xE7, + // Bytes 11c0 - 11ff + 0xBD, 0x91, 0x43, 0xE7, 0xBD, 0xB2, 0x43, 0xE7, + 0xBD, 0xB9, 0x43, 0xE7, 0xBD, 0xBA, 0x43, 0xE7, + 0xBE, 0x85, 0x43, 0xE7, 0xBE, 0x8A, 0x43, 0xE7, + 0xBE, 0x95, 0x43, 0xE7, 0xBE, 0x9A, 0x43, 0xE7, + 0xBE, 0xBD, 0x43, 0xE7, 0xBF, 0xBA, 0x43, 0xE8, + 0x80, 0x81, 0x43, 0xE8, 0x80, 0x85, 0x43, 0xE8, + 0x80, 0x8C, 0x43, 0xE8, 0x80, 0x92, 0x43, 0xE8, + 0x80, 0xB3, 0x43, 0xE8, 0x81, 0x86, 0x43, 0xE8, + // Bytes 1200 - 123f + 0x81, 0xA0, 0x43, 0xE8, 0x81, 0xAF, 0x43, 0xE8, + 0x81, 0xB0, 0x43, 0xE8, 0x81, 0xBE, 0x43, 0xE8, + 0x81, 0xBF, 0x43, 0xE8, 0x82, 0x89, 0x43, 0xE8, + 0x82, 0x8B, 0x43, 0xE8, 0x82, 0xAD, 0x43, 0xE8, + 0x82, 0xB2, 0x43, 0xE8, 0x84, 0x83, 0x43, 0xE8, + 0x84, 0xBE, 0x43, 0xE8, 0x87, 0x98, 0x43, 0xE8, + 0x87, 0xA3, 0x43, 0xE8, 0x87, 0xA8, 0x43, 0xE8, + 0x87, 0xAA, 0x43, 0xE8, 0x87, 0xAD, 0x43, 0xE8, + // Bytes 1240 - 127f + 0x87, 0xB3, 0x43, 0xE8, 0x87, 0xBC, 0x43, 0xE8, + 0x88, 0x81, 0x43, 0xE8, 0x88, 0x84, 0x43, 0xE8, + 0x88, 0x8C, 0x43, 0xE8, 0x88, 0x98, 0x43, 0xE8, + 0x88, 0x9B, 0x43, 0xE8, 0x88, 0x9F, 0x43, 0xE8, + 0x89, 0xAE, 0x43, 0xE8, 0x89, 0xAF, 0x43, 0xE8, + 0x89, 0xB2, 0x43, 0xE8, 0x89, 0xB8, 0x43, 0xE8, + 0x89, 0xB9, 0x43, 0xE8, 0x8A, 0x8B, 0x43, 0xE8, + 0x8A, 0x91, 0x43, 0xE8, 0x8A, 0x9D, 0x43, 0xE8, + // Bytes 1280 - 12bf + 0x8A, 0xB1, 0x43, 0xE8, 0x8A, 0xB3, 0x43, 0xE8, + 0x8A, 0xBD, 0x43, 0xE8, 0x8B, 0xA5, 0x43, 0xE8, + 0x8B, 0xA6, 0x43, 0xE8, 0x8C, 0x9D, 0x43, 0xE8, + 0x8C, 0xA3, 0x43, 0xE8, 0x8C, 0xB6, 0x43, 0xE8, + 0x8D, 0x92, 0x43, 0xE8, 0x8D, 0x93, 0x43, 0xE8, + 0x8D, 0xA3, 0x43, 0xE8, 0x8E, 0xAD, 0x43, 0xE8, + 0x8E, 0xBD, 0x43, 0xE8, 0x8F, 0x89, 0x43, 0xE8, + 0x8F, 0x8A, 0x43, 0xE8, 0x8F, 0x8C, 0x43, 0xE8, + // Bytes 12c0 - 12ff + 0x8F, 0x9C, 0x43, 0xE8, 0x8F, 0xA7, 0x43, 0xE8, + 0x8F, 0xAF, 0x43, 0xE8, 0x8F, 0xB1, 0x43, 0xE8, + 0x90, 0xBD, 0x43, 0xE8, 0x91, 0x89, 0x43, 0xE8, + 0x91, 0x97, 0x43, 0xE8, 0x93, 0xAE, 0x43, 0xE8, + 0x93, 0xB1, 0x43, 0xE8, 0x93, 0xB3, 0x43, 0xE8, + 0x93, 0xBC, 0x43, 0xE8, 0x94, 0x96, 0x43, 0xE8, + 0x95, 0xA4, 0x43, 0xE8, 0x97, 0x8D, 0x43, 0xE8, + 0x97, 0xBA, 0x43, 0xE8, 0x98, 0x86, 0x43, 0xE8, + // Bytes 1300 - 133f + 0x98, 0x92, 0x43, 0xE8, 0x98, 0xAD, 0x43, 0xE8, + 0x98, 0xBF, 0x43, 0xE8, 0x99, 0x8D, 0x43, 0xE8, + 0x99, 0x90, 0x43, 0xE8, 0x99, 0x9C, 0x43, 0xE8, + 0x99, 0xA7, 0x43, 0xE8, 0x99, 0xA9, 0x43, 0xE8, + 0x99, 0xAB, 0x43, 0xE8, 0x9A, 0x88, 0x43, 0xE8, + 0x9A, 0xA9, 0x43, 0xE8, 0x9B, 0xA2, 0x43, 0xE8, + 0x9C, 0x8E, 0x43, 0xE8, 0x9C, 0xA8, 0x43, 0xE8, + 0x9D, 0xAB, 0x43, 0xE8, 0x9D, 0xB9, 0x43, 0xE8, + // Bytes 1340 - 137f + 0x9E, 0x86, 0x43, 0xE8, 0x9E, 0xBA, 0x43, 0xE8, + 0x9F, 0xA1, 0x43, 0xE8, 0xA0, 0x81, 0x43, 0xE8, + 0xA0, 0x9F, 0x43, 0xE8, 0xA1, 0x80, 0x43, 0xE8, + 0xA1, 0x8C, 0x43, 0xE8, 0xA1, 0xA0, 0x43, 0xE8, + 0xA1, 0xA3, 0x43, 0xE8, 0xA3, 0x82, 0x43, 0xE8, + 0xA3, 0x8F, 0x43, 0xE8, 0xA3, 0x97, 0x43, 0xE8, + 0xA3, 0x9E, 0x43, 0xE8, 0xA3, 0xA1, 0x43, 0xE8, + 0xA3, 0xB8, 0x43, 0xE8, 0xA3, 0xBA, 0x43, 0xE8, + // Bytes 1380 - 13bf + 0xA4, 0x90, 0x43, 0xE8, 0xA5, 0x81, 0x43, 0xE8, + 0xA5, 0xA4, 0x43, 0xE8, 0xA5, 0xBE, 0x43, 0xE8, + 0xA6, 0x86, 0x43, 0xE8, 0xA6, 0x8B, 0x43, 0xE8, + 0xA6, 0x96, 0x43, 0xE8, 0xA7, 0x92, 0x43, 0xE8, + 0xA7, 0xA3, 0x43, 0xE8, 0xA8, 0x80, 0x43, 0xE8, + 0xAA, 0xA0, 0x43, 0xE8, 0xAA, 0xAA, 0x43, 0xE8, + 0xAA, 0xBF, 0x43, 0xE8, 0xAB, 0x8B, 0x43, 0xE8, + 0xAB, 0x92, 0x43, 0xE8, 0xAB, 0x96, 0x43, 0xE8, + // Bytes 13c0 - 13ff + 0xAB, 0xAD, 0x43, 0xE8, 0xAB, 0xB8, 0x43, 0xE8, + 0xAB, 0xBE, 0x43, 0xE8, 0xAC, 0x81, 0x43, 0xE8, + 0xAC, 0xB9, 0x43, 0xE8, 0xAD, 0x98, 0x43, 0xE8, + 0xAE, 0x80, 0x43, 0xE8, 0xAE, 0x8A, 0x43, 0xE8, + 0xB0, 0xB7, 0x43, 0xE8, 0xB1, 0x86, 0x43, 0xE8, + 0xB1, 0x88, 0x43, 0xE8, 0xB1, 0x95, 0x43, 0xE8, + 0xB1, 0xB8, 0x43, 0xE8, 0xB2, 0x9D, 0x43, 0xE8, + 0xB2, 0xA1, 0x43, 0xE8, 0xB2, 0xA9, 0x43, 0xE8, + // Bytes 1400 - 143f + 0xB2, 0xAB, 0x43, 0xE8, 0xB3, 0x81, 0x43, 0xE8, + 0xB3, 0x82, 0x43, 0xE8, 0xB3, 0x87, 0x43, 0xE8, + 0xB3, 0x88, 0x43, 0xE8, 0xB3, 0x93, 0x43, 0xE8, + 0xB4, 0x88, 0x43, 0xE8, 0xB4, 0x9B, 0x43, 0xE8, + 0xB5, 0xA4, 0x43, 0xE8, 0xB5, 0xB0, 0x43, 0xE8, + 0xB5, 0xB7, 0x43, 0xE8, 0xB6, 0xB3, 0x43, 0xE8, + 0xB6, 0xBC, 0x43, 0xE8, 0xB7, 0x8B, 0x43, 0xE8, + 0xB7, 0xAF, 0x43, 0xE8, 0xB7, 0xB0, 0x43, 0xE8, + // Bytes 1440 - 147f + 0xBA, 0xAB, 0x43, 0xE8, 0xBB, 0x8A, 0x43, 0xE8, + 0xBB, 0x94, 0x43, 0xE8, 0xBC, 0xA6, 0x43, 0xE8, + 0xBC, 0xAA, 0x43, 0xE8, 0xBC, 0xB8, 0x43, 0xE8, + 0xBC, 0xBB, 0x43, 0xE8, 0xBD, 0xA2, 0x43, 0xE8, + 0xBE, 0x9B, 0x43, 0xE8, 0xBE, 0x9E, 0x43, 0xE8, + 0xBE, 0xB0, 0x43, 0xE8, 0xBE, 0xB5, 0x43, 0xE8, + 0xBE, 0xB6, 0x43, 0xE9, 0x80, 0xA3, 0x43, 0xE9, + 0x80, 0xB8, 0x43, 0xE9, 0x81, 0x8A, 0x43, 0xE9, + // Bytes 1480 - 14bf + 0x81, 0xA9, 0x43, 0xE9, 0x81, 0xB2, 0x43, 0xE9, + 0x81, 0xBC, 0x43, 0xE9, 0x82, 0x8F, 0x43, 0xE9, + 0x82, 0x91, 0x43, 0xE9, 0x82, 0x94, 0x43, 0xE9, + 0x83, 0x8E, 0x43, 0xE9, 0x83, 0x9E, 0x43, 0xE9, + 0x83, 0xB1, 0x43, 0xE9, 0x83, 0xBD, 0x43, 0xE9, + 0x84, 0x91, 0x43, 0xE9, 0x84, 0x9B, 0x43, 0xE9, + 0x85, 0x89, 0x43, 0xE9, 0x85, 0xAA, 0x43, 0xE9, + 0x86, 0x99, 0x43, 0xE9, 0x86, 0xB4, 0x43, 0xE9, + // Bytes 14c0 - 14ff + 0x87, 0x86, 0x43, 0xE9, 0x87, 0x8C, 0x43, 0xE9, + 0x87, 0x8F, 0x43, 0xE9, 0x87, 0x91, 0x43, 0xE9, + 0x88, 0xB4, 0x43, 0xE9, 0x88, 0xB8, 0x43, 0xE9, + 0x89, 0xB6, 0x43, 0xE9, 0x89, 0xBC, 0x43, 0xE9, + 0x8B, 0x97, 0x43, 0xE9, 0x8B, 0x98, 0x43, 0xE9, + 0x8C, 0x84, 0x43, 0xE9, 0x8D, 0x8A, 0x43, 0xE9, + 0x8F, 0xB9, 0x43, 0xE9, 0x90, 0x95, 0x43, 0xE9, + 0x95, 0xB7, 0x43, 0xE9, 0x96, 0x80, 0x43, 0xE9, + // Bytes 1500 - 153f + 0x96, 0x8B, 0x43, 0xE9, 0x96, 0xAD, 0x43, 0xE9, + 0x96, 0xB7, 0x43, 0xE9, 0x98, 0x9C, 0x43, 0xE9, + 0x98, 0xAE, 0x43, 0xE9, 0x99, 0x8B, 0x43, 0xE9, + 0x99, 0x8D, 0x43, 0xE9, 0x99, 0xB5, 0x43, 0xE9, + 0x99, 0xB8, 0x43, 0xE9, 0x99, 0xBC, 0x43, 0xE9, + 0x9A, 0x86, 0x43, 0xE9, 0x9A, 0xA3, 0x43, 0xE9, + 0x9A, 0xB6, 0x43, 0xE9, 0x9A, 0xB7, 0x43, 0xE9, + 0x9A, 0xB8, 0x43, 0xE9, 0x9A, 0xB9, 0x43, 0xE9, + // Bytes 1540 - 157f + 0x9B, 0x83, 0x43, 0xE9, 0x9B, 0xA2, 0x43, 0xE9, + 0x9B, 0xA3, 0x43, 0xE9, 0x9B, 0xA8, 0x43, 0xE9, + 0x9B, 0xB6, 0x43, 0xE9, 0x9B, 0xB7, 0x43, 0xE9, + 0x9C, 0xA3, 0x43, 0xE9, 0x9C, 0xB2, 0x43, 0xE9, + 0x9D, 0x88, 0x43, 0xE9, 0x9D, 0x91, 0x43, 0xE9, + 0x9D, 0x96, 0x43, 0xE9, 0x9D, 0x9E, 0x43, 0xE9, + 0x9D, 0xA2, 0x43, 0xE9, 0x9D, 0xA9, 0x43, 0xE9, + 0x9F, 0x8B, 0x43, 0xE9, 0x9F, 0x9B, 0x43, 0xE9, + // Bytes 1580 - 15bf + 0x9F, 0xA0, 0x43, 0xE9, 0x9F, 0xAD, 0x43, 0xE9, + 0x9F, 0xB3, 0x43, 0xE9, 0x9F, 0xBF, 0x43, 0xE9, + 0xA0, 0x81, 0x43, 0xE9, 0xA0, 0x85, 0x43, 0xE9, + 0xA0, 0x8B, 0x43, 0xE9, 0xA0, 0x98, 0x43, 0xE9, + 0xA0, 0xA9, 0x43, 0xE9, 0xA0, 0xBB, 0x43, 0xE9, + 0xA1, 0x9E, 0x43, 0xE9, 0xA2, 0xA8, 0x43, 0xE9, + 0xA3, 0x9B, 0x43, 0xE9, 0xA3, 0x9F, 0x43, 0xE9, + 0xA3, 0xA2, 0x43, 0xE9, 0xA3, 0xAF, 0x43, 0xE9, + // Bytes 15c0 - 15ff + 0xA3, 0xBC, 0x43, 0xE9, 0xA4, 0xA8, 0x43, 0xE9, + 0xA4, 0xA9, 0x43, 0xE9, 0xA6, 0x96, 0x43, 0xE9, + 0xA6, 0x99, 0x43, 0xE9, 0xA6, 0xA7, 0x43, 0xE9, + 0xA6, 0xAC, 0x43, 0xE9, 0xA7, 0x82, 0x43, 0xE9, + 0xA7, 0xB1, 0x43, 0xE9, 0xA7, 0xBE, 0x43, 0xE9, + 0xA9, 0xAA, 0x43, 0xE9, 0xAA, 0xA8, 0x43, 0xE9, + 0xAB, 0x98, 0x43, 0xE9, 0xAB, 0x9F, 0x43, 0xE9, + 0xAC, 0x92, 0x43, 0xE9, 0xAC, 0xA5, 0x43, 0xE9, + // Bytes 1600 - 163f + 0xAC, 0xAF, 0x43, 0xE9, 0xAC, 0xB2, 0x43, 0xE9, + 0xAC, 0xBC, 0x43, 0xE9, 0xAD, 0x9A, 0x43, 0xE9, + 0xAD, 0xAF, 0x43, 0xE9, 0xB1, 0x80, 0x43, 0xE9, + 0xB1, 0x97, 0x43, 0xE9, 0xB3, 0xA5, 0x43, 0xE9, + 0xB3, 0xBD, 0x43, 0xE9, 0xB5, 0xA7, 0x43, 0xE9, + 0xB6, 0xB4, 0x43, 0xE9, 0xB7, 0xBA, 0x43, 0xE9, + 0xB8, 0x9E, 0x43, 0xE9, 0xB9, 0xB5, 0x43, 0xE9, + 0xB9, 0xBF, 0x43, 0xE9, 0xBA, 0x97, 0x43, 0xE9, + // Bytes 1640 - 167f + 0xBA, 0x9F, 0x43, 0xE9, 0xBA, 0xA5, 0x43, 0xE9, + 0xBA, 0xBB, 0x43, 0xE9, 0xBB, 0x83, 0x43, 0xE9, + 0xBB, 0x8D, 0x43, 0xE9, 0xBB, 0x8E, 0x43, 0xE9, + 0xBB, 0x91, 0x43, 0xE9, 0xBB, 0xB9, 0x43, 0xE9, + 0xBB, 0xBD, 0x43, 0xE9, 0xBB, 0xBE, 0x43, 0xE9, + 0xBC, 0x85, 0x43, 0xE9, 0xBC, 0x8E, 0x43, 0xE9, + 0xBC, 0x8F, 0x43, 0xE9, 0xBC, 0x93, 0x43, 0xE9, + 0xBC, 0x96, 0x43, 0xE9, 0xBC, 0xA0, 0x43, 0xE9, + // Bytes 1680 - 16bf + 0xBC, 0xBB, 0x43, 0xE9, 0xBD, 0x83, 0x43, 0xE9, + 0xBD, 0x8A, 0x43, 0xE9, 0xBD, 0x92, 0x43, 0xE9, + 0xBE, 0x8D, 0x43, 0xE9, 0xBE, 0x8E, 0x43, 0xE9, + 0xBE, 0x9C, 0x43, 0xE9, 0xBE, 0x9F, 0x43, 0xE9, + 0xBE, 0xA0, 0x43, 0xEA, 0x9D, 0xAF, 0x44, 0xF0, + 0xA0, 0x84, 0xA2, 0x44, 0xF0, 0xA0, 0x94, 0x9C, + 0x44, 0xF0, 0xA0, 0x94, 0xA5, 0x44, 0xF0, 0xA0, + 0x95, 0x8B, 0x44, 0xF0, 0xA0, 0x98, 0xBA, 0x44, + // Bytes 16c0 - 16ff + 0xF0, 0xA0, 0xA0, 0x84, 0x44, 0xF0, 0xA0, 0xA3, + 0x9E, 0x44, 0xF0, 0xA0, 0xA8, 0xAC, 0x44, 0xF0, + 0xA0, 0xAD, 0xA3, 0x44, 0xF0, 0xA1, 0x93, 0xA4, + 0x44, 0xF0, 0xA1, 0x9A, 0xA8, 0x44, 0xF0, 0xA1, + 0x9B, 0xAA, 0x44, 0xF0, 0xA1, 0xA7, 0x88, 0x44, + 0xF0, 0xA1, 0xAC, 0x98, 0x44, 0xF0, 0xA1, 0xB4, + 0x8B, 0x44, 0xF0, 0xA1, 0xB7, 0xA4, 0x44, 0xF0, + 0xA1, 0xB7, 0xA6, 0x44, 0xF0, 0xA2, 0x86, 0x83, + // Bytes 1700 - 173f + 0x44, 0xF0, 0xA2, 0x86, 0x9F, 0x44, 0xF0, 0xA2, + 0x8C, 0xB1, 0x44, 0xF0, 0xA2, 0x9B, 0x94, 0x44, + 0xF0, 0xA2, 0xA1, 0x84, 0x44, 0xF0, 0xA2, 0xA1, + 0x8A, 0x44, 0xF0, 0xA2, 0xAC, 0x8C, 0x44, 0xF0, + 0xA2, 0xAF, 0xB1, 0x44, 0xF0, 0xA3, 0x80, 0x8A, + 0x44, 0xF0, 0xA3, 0x8A, 0xB8, 0x44, 0xF0, 0xA3, + 0x8D, 0x9F, 0x44, 0xF0, 0xA3, 0x8E, 0x93, 0x44, + 0xF0, 0xA3, 0x8E, 0x9C, 0x44, 0xF0, 0xA3, 0x8F, + // Bytes 1740 - 177f + 0x83, 0x44, 0xF0, 0xA3, 0x8F, 0x95, 0x44, 0xF0, + 0xA3, 0x91, 0xAD, 0x44, 0xF0, 0xA3, 0x9A, 0xA3, + 0x44, 0xF0, 0xA3, 0xA2, 0xA7, 0x44, 0xF0, 0xA3, + 0xAA, 0x8D, 0x44, 0xF0, 0xA3, 0xAB, 0xBA, 0x44, + 0xF0, 0xA3, 0xB2, 0xBC, 0x44, 0xF0, 0xA3, 0xB4, + 0x9E, 0x44, 0xF0, 0xA3, 0xBB, 0x91, 0x44, 0xF0, + 0xA3, 0xBD, 0x9E, 0x44, 0xF0, 0xA3, 0xBE, 0x8E, + 0x44, 0xF0, 0xA4, 0x89, 0xA3, 0x44, 0xF0, 0xA4, + // Bytes 1780 - 17bf + 0x8B, 0xAE, 0x44, 0xF0, 0xA4, 0x8E, 0xAB, 0x44, + 0xF0, 0xA4, 0x98, 0x88, 0x44, 0xF0, 0xA4, 0x9C, + 0xB5, 0x44, 0xF0, 0xA4, 0xA0, 0x94, 0x44, 0xF0, + 0xA4, 0xB0, 0xB6, 0x44, 0xF0, 0xA4, 0xB2, 0x92, + 0x44, 0xF0, 0xA4, 0xBE, 0xA1, 0x44, 0xF0, 0xA4, + 0xBE, 0xB8, 0x44, 0xF0, 0xA5, 0x81, 0x84, 0x44, + 0xF0, 0xA5, 0x83, 0xB2, 0x44, 0xF0, 0xA5, 0x83, + 0xB3, 0x44, 0xF0, 0xA5, 0x84, 0x99, 0x44, 0xF0, + // Bytes 17c0 - 17ff + 0xA5, 0x84, 0xB3, 0x44, 0xF0, 0xA5, 0x89, 0x89, + 0x44, 0xF0, 0xA5, 0x90, 0x9D, 0x44, 0xF0, 0xA5, + 0x98, 0xA6, 0x44, 0xF0, 0xA5, 0x9A, 0x9A, 0x44, + 0xF0, 0xA5, 0x9B, 0x85, 0x44, 0xF0, 0xA5, 0xA5, + 0xBC, 0x44, 0xF0, 0xA5, 0xAA, 0xA7, 0x44, 0xF0, + 0xA5, 0xAE, 0xAB, 0x44, 0xF0, 0xA5, 0xB2, 0x80, + 0x44, 0xF0, 0xA5, 0xB3, 0x90, 0x44, 0xF0, 0xA5, + 0xBE, 0x86, 0x44, 0xF0, 0xA6, 0x87, 0x9A, 0x44, + // Bytes 1800 - 183f + 0xF0, 0xA6, 0x88, 0xA8, 0x44, 0xF0, 0xA6, 0x89, + 0x87, 0x44, 0xF0, 0xA6, 0x8B, 0x99, 0x44, 0xF0, + 0xA6, 0x8C, 0xBE, 0x44, 0xF0, 0xA6, 0x93, 0x9A, + 0x44, 0xF0, 0xA6, 0x94, 0xA3, 0x44, 0xF0, 0xA6, + 0x96, 0xA8, 0x44, 0xF0, 0xA6, 0x9E, 0xA7, 0x44, + 0xF0, 0xA6, 0x9E, 0xB5, 0x44, 0xF0, 0xA6, 0xAC, + 0xBC, 0x44, 0xF0, 0xA6, 0xB0, 0xB6, 0x44, 0xF0, + 0xA6, 0xB3, 0x95, 0x44, 0xF0, 0xA6, 0xB5, 0xAB, + // Bytes 1840 - 187f + 0x44, 0xF0, 0xA6, 0xBC, 0xAC, 0x44, 0xF0, 0xA6, + 0xBE, 0xB1, 0x44, 0xF0, 0xA7, 0x83, 0x92, 0x44, + 0xF0, 0xA7, 0x8F, 0x8A, 0x44, 0xF0, 0xA7, 0x99, + 0xA7, 0x44, 0xF0, 0xA7, 0xA2, 0xAE, 0x44, 0xF0, + 0xA7, 0xA5, 0xA6, 0x44, 0xF0, 0xA7, 0xB2, 0xA8, + 0x44, 0xF0, 0xA7, 0xBB, 0x93, 0x44, 0xF0, 0xA7, + 0xBC, 0xAF, 0x44, 0xF0, 0xA8, 0x97, 0x92, 0x44, + 0xF0, 0xA8, 0x97, 0xAD, 0x44, 0xF0, 0xA8, 0x9C, + // Bytes 1880 - 18bf + 0xAE, 0x44, 0xF0, 0xA8, 0xAF, 0xBA, 0x44, 0xF0, + 0xA8, 0xB5, 0xB7, 0x44, 0xF0, 0xA9, 0x85, 0x85, + 0x44, 0xF0, 0xA9, 0x87, 0x9F, 0x44, 0xF0, 0xA9, + 0x88, 0x9A, 0x44, 0xF0, 0xA9, 0x90, 0x8A, 0x44, + 0xF0, 0xA9, 0x92, 0x96, 0x44, 0xF0, 0xA9, 0x96, + 0xB6, 0x44, 0xF0, 0xA9, 0xAC, 0xB0, 0x44, 0xF0, + 0xAA, 0x83, 0x8E, 0x44, 0xF0, 0xAA, 0x84, 0x85, + 0x44, 0xF0, 0xAA, 0x88, 0x8E, 0x44, 0xF0, 0xAA, + // Bytes 18c0 - 18ff + 0x8A, 0x91, 0x44, 0xF0, 0xAA, 0x8E, 0x92, 0x44, + 0xF0, 0xAA, 0x98, 0x80, 0x06, 0xE0, 0xA7, 0x87, + 0xE0, 0xA6, 0xBE, 0x06, 0xE0, 0xA7, 0x87, 0xE0, + 0xA7, 0x97, 0x06, 0xE0, 0xAD, 0x87, 0xE0, 0xAC, + 0xBE, 0x06, 0xE0, 0xAD, 0x87, 0xE0, 0xAD, 0x96, + 0x06, 0xE0, 0xAD, 0x87, 0xE0, 0xAD, 0x97, 0x06, + 0xE0, 0xAE, 0x92, 0xE0, 0xAF, 0x97, 0x06, 0xE0, + 0xAF, 0x86, 0xE0, 0xAE, 0xBE, 0x06, 0xE0, 0xAF, + // Bytes 1900 - 193f + 0x86, 0xE0, 0xAF, 0x97, 0x06, 0xE0, 0xAF, 0x87, + 0xE0, 0xAE, 0xBE, 0x06, 0xE0, 0xB2, 0xBF, 0xE0, + 0xB3, 0x95, 0x06, 0xE0, 0xB3, 0x86, 0xE0, 0xB3, + 0x95, 0x06, 0xE0, 0xB3, 0x86, 0xE0, 0xB3, 0x96, + 0x06, 0xE0, 0xB5, 0x86, 0xE0, 0xB4, 0xBE, 0x06, + 0xE0, 0xB5, 0x86, 0xE0, 0xB5, 0x97, 0x06, 0xE0, + 0xB5, 0x87, 0xE0, 0xB4, 0xBE, 0x06, 0xE0, 0xB7, + 0x99, 0xE0, 0xB7, 0x9F, 0x06, 0xE1, 0x80, 0xA5, + // Bytes 1940 - 197f + 0xE1, 0x80, 0xAE, 0x06, 0xE1, 0xAC, 0x85, 0xE1, + 0xAC, 0xB5, 0x06, 0xE1, 0xAC, 0x87, 0xE1, 0xAC, + 0xB5, 0x06, 0xE1, 0xAC, 0x89, 0xE1, 0xAC, 0xB5, + 0x06, 0xE1, 0xAC, 0x8B, 0xE1, 0xAC, 0xB5, 0x06, + 0xE1, 0xAC, 0x8D, 0xE1, 0xAC, 0xB5, 0x06, 0xE1, + 0xAC, 0x91, 0xE1, 0xAC, 0xB5, 0x06, 0xE1, 0xAC, + 0xBA, 0xE1, 0xAC, 0xB5, 0x06, 0xE1, 0xAC, 0xBC, + 0xE1, 0xAC, 0xB5, 0x06, 0xE1, 0xAC, 0xBE, 0xE1, + // Bytes 1980 - 19bf + 0xAC, 0xB5, 0x06, 0xE1, 0xAC, 0xBF, 0xE1, 0xAC, + 0xB5, 0x06, 0xE1, 0xAD, 0x82, 0xE1, 0xAC, 0xB5, + 0x08, 0xF0, 0x91, 0x84, 0xB1, 0xF0, 0x91, 0x84, + 0xA7, 0x08, 0xF0, 0x91, 0x84, 0xB2, 0xF0, 0x91, + 0x84, 0xA7, 0x09, 0xE0, 0xB3, 0x86, 0xE0, 0xB3, + 0x82, 0xE0, 0xB3, 0x95, 0x42, 0x21, 0x21, 0x42, + 0x21, 0x3F, 0x42, 0x2E, 0x2E, 0x42, 0x30, 0x2C, + 0x42, 0x30, 0x2E, 0x42, 0x31, 0x2C, 0x42, 0x31, + // Bytes 19c0 - 19ff + 0x2E, 0x42, 0x31, 0x30, 0x42, 0x31, 0x31, 0x42, + 0x31, 0x32, 0x42, 0x31, 0x33, 0x42, 0x31, 0x34, + 0x42, 0x31, 0x35, 0x42, 0x31, 0x36, 0x42, 0x31, + 0x37, 0x42, 0x31, 0x38, 0x42, 0x31, 0x39, 0x42, + 0x32, 0x2C, 0x42, 0x32, 0x2E, 0x42, 0x32, 0x30, + 0x42, 0x32, 0x31, 0x42, 0x32, 0x32, 0x42, 0x32, + 0x33, 0x42, 0x32, 0x34, 0x42, 0x32, 0x35, 0x42, + 0x32, 0x36, 0x42, 0x32, 0x37, 0x42, 0x32, 0x38, + // Bytes 1a00 - 1a3f + 0x42, 0x32, 0x39, 0x42, 0x33, 0x2C, 0x42, 0x33, + 0x2E, 0x42, 0x33, 0x30, 0x42, 0x33, 0x31, 0x42, + 0x33, 0x32, 0x42, 0x33, 0x33, 0x42, 0x33, 0x34, + 0x42, 0x33, 0x35, 0x42, 0x33, 0x36, 0x42, 0x33, + 0x37, 0x42, 0x33, 0x38, 0x42, 0x33, 0x39, 0x42, + 0x34, 0x2C, 0x42, 0x34, 0x2E, 0x42, 0x34, 0x30, + 0x42, 0x34, 0x31, 0x42, 0x34, 0x32, 0x42, 0x34, + 0x33, 0x42, 0x34, 0x34, 0x42, 0x34, 0x35, 0x42, + // Bytes 1a40 - 1a7f + 0x34, 0x36, 0x42, 0x34, 0x37, 0x42, 0x34, 0x38, + 0x42, 0x34, 0x39, 0x42, 0x35, 0x2C, 0x42, 0x35, + 0x2E, 0x42, 0x35, 0x30, 0x42, 0x36, 0x2C, 0x42, + 0x36, 0x2E, 0x42, 0x37, 0x2C, 0x42, 0x37, 0x2E, + 0x42, 0x38, 0x2C, 0x42, 0x38, 0x2E, 0x42, 0x39, + 0x2C, 0x42, 0x39, 0x2E, 0x42, 0x3D, 0x3D, 0x42, + 0x3F, 0x21, 0x42, 0x3F, 0x3F, 0x42, 0x41, 0x55, + 0x42, 0x42, 0x71, 0x42, 0x43, 0x44, 0x42, 0x44, + // Bytes 1a80 - 1abf + 0x4A, 0x42, 0x44, 0x5A, 0x42, 0x44, 0x7A, 0x42, + 0x47, 0x42, 0x42, 0x47, 0x79, 0x42, 0x48, 0x50, + 0x42, 0x48, 0x56, 0x42, 0x48, 0x67, 0x42, 0x48, + 0x7A, 0x42, 0x49, 0x49, 0x42, 0x49, 0x4A, 0x42, + 0x49, 0x55, 0x42, 0x49, 0x56, 0x42, 0x49, 0x58, + 0x42, 0x4B, 0x42, 0x42, 0x4B, 0x4B, 0x42, 0x4B, + 0x4D, 0x42, 0x4C, 0x4A, 0x42, 0x4C, 0x6A, 0x42, + 0x4D, 0x42, 0x42, 0x4D, 0x43, 0x42, 0x4D, 0x44, + // Bytes 1ac0 - 1aff + 0x42, 0x4D, 0x56, 0x42, 0x4D, 0x57, 0x42, 0x4E, + 0x4A, 0x42, 0x4E, 0x6A, 0x42, 0x4E, 0x6F, 0x42, + 0x50, 0x48, 0x42, 0x50, 0x52, 0x42, 0x50, 0x61, + 0x42, 0x52, 0x73, 0x42, 0x53, 0x44, 0x42, 0x53, + 0x4D, 0x42, 0x53, 0x53, 0x42, 0x53, 0x76, 0x42, + 0x54, 0x4D, 0x42, 0x56, 0x49, 0x42, 0x57, 0x43, + 0x42, 0x57, 0x5A, 0x42, 0x57, 0x62, 0x42, 0x58, + 0x49, 0x42, 0x63, 0x63, 0x42, 0x63, 0x64, 0x42, + // Bytes 1b00 - 1b3f + 0x63, 0x6D, 0x42, 0x64, 0x42, 0x42, 0x64, 0x61, + 0x42, 0x64, 0x6C, 0x42, 0x64, 0x6D, 0x42, 0x64, + 0x7A, 0x42, 0x65, 0x56, 0x42, 0x66, 0x66, 0x42, + 0x66, 0x69, 0x42, 0x66, 0x6C, 0x42, 0x66, 0x6D, + 0x42, 0x68, 0x61, 0x42, 0x69, 0x69, 0x42, 0x69, + 0x6A, 0x42, 0x69, 0x6E, 0x42, 0x69, 0x76, 0x42, + 0x69, 0x78, 0x42, 0x6B, 0x41, 0x42, 0x6B, 0x56, + 0x42, 0x6B, 0x57, 0x42, 0x6B, 0x67, 0x42, 0x6B, + // Bytes 1b40 - 1b7f + 0x6C, 0x42, 0x6B, 0x6D, 0x42, 0x6B, 0x74, 0x42, + 0x6C, 0x6A, 0x42, 0x6C, 0x6D, 0x42, 0x6C, 0x6E, + 0x42, 0x6C, 0x78, 0x42, 0x6D, 0x32, 0x42, 0x6D, + 0x33, 0x42, 0x6D, 0x41, 0x42, 0x6D, 0x56, 0x42, + 0x6D, 0x57, 0x42, 0x6D, 0x62, 0x42, 0x6D, 0x67, + 0x42, 0x6D, 0x6C, 0x42, 0x6D, 0x6D, 0x42, 0x6D, + 0x73, 0x42, 0x6E, 0x41, 0x42, 0x6E, 0x46, 0x42, + 0x6E, 0x56, 0x42, 0x6E, 0x57, 0x42, 0x6E, 0x6A, + // Bytes 1b80 - 1bbf + 0x42, 0x6E, 0x6D, 0x42, 0x6E, 0x73, 0x42, 0x6F, + 0x56, 0x42, 0x70, 0x41, 0x42, 0x70, 0x46, 0x42, + 0x70, 0x56, 0x42, 0x70, 0x57, 0x42, 0x70, 0x63, + 0x42, 0x70, 0x73, 0x42, 0x73, 0x72, 0x42, 0x73, + 0x74, 0x42, 0x76, 0x69, 0x42, 0x78, 0x69, 0x43, + 0x28, 0x31, 0x29, 0x43, 0x28, 0x32, 0x29, 0x43, + 0x28, 0x33, 0x29, 0x43, 0x28, 0x34, 0x29, 0x43, + 0x28, 0x35, 0x29, 0x43, 0x28, 0x36, 0x29, 0x43, + // Bytes 1bc0 - 1bff + 0x28, 0x37, 0x29, 0x43, 0x28, 0x38, 0x29, 0x43, + 0x28, 0x39, 0x29, 0x43, 0x28, 0x41, 0x29, 0x43, + 0x28, 0x42, 0x29, 0x43, 0x28, 0x43, 0x29, 0x43, + 0x28, 0x44, 0x29, 0x43, 0x28, 0x45, 0x29, 0x43, + 0x28, 0x46, 0x29, 0x43, 0x28, 0x47, 0x29, 0x43, + 0x28, 0x48, 0x29, 0x43, 0x28, 0x49, 0x29, 0x43, + 0x28, 0x4A, 0x29, 0x43, 0x28, 0x4B, 0x29, 0x43, + 0x28, 0x4C, 0x29, 0x43, 0x28, 0x4D, 0x29, 0x43, + // Bytes 1c00 - 1c3f + 0x28, 0x4E, 0x29, 0x43, 0x28, 0x4F, 0x29, 0x43, + 0x28, 0x50, 0x29, 0x43, 0x28, 0x51, 0x29, 0x43, + 0x28, 0x52, 0x29, 0x43, 0x28, 0x53, 0x29, 0x43, + 0x28, 0x54, 0x29, 0x43, 0x28, 0x55, 0x29, 0x43, + 0x28, 0x56, 0x29, 0x43, 0x28, 0x57, 0x29, 0x43, + 0x28, 0x58, 0x29, 0x43, 0x28, 0x59, 0x29, 0x43, + 0x28, 0x5A, 0x29, 0x43, 0x28, 0x61, 0x29, 0x43, + 0x28, 0x62, 0x29, 0x43, 0x28, 0x63, 0x29, 0x43, + // Bytes 1c40 - 1c7f + 0x28, 0x64, 0x29, 0x43, 0x28, 0x65, 0x29, 0x43, + 0x28, 0x66, 0x29, 0x43, 0x28, 0x67, 0x29, 0x43, + 0x28, 0x68, 0x29, 0x43, 0x28, 0x69, 0x29, 0x43, + 0x28, 0x6A, 0x29, 0x43, 0x28, 0x6B, 0x29, 0x43, + 0x28, 0x6C, 0x29, 0x43, 0x28, 0x6D, 0x29, 0x43, + 0x28, 0x6E, 0x29, 0x43, 0x28, 0x6F, 0x29, 0x43, + 0x28, 0x70, 0x29, 0x43, 0x28, 0x71, 0x29, 0x43, + 0x28, 0x72, 0x29, 0x43, 0x28, 0x73, 0x29, 0x43, + // Bytes 1c80 - 1cbf + 0x28, 0x74, 0x29, 0x43, 0x28, 0x75, 0x29, 0x43, + 0x28, 0x76, 0x29, 0x43, 0x28, 0x77, 0x29, 0x43, + 0x28, 0x78, 0x29, 0x43, 0x28, 0x79, 0x29, 0x43, + 0x28, 0x7A, 0x29, 0x43, 0x2E, 0x2E, 0x2E, 0x43, + 0x31, 0x30, 0x2E, 0x43, 0x31, 0x31, 0x2E, 0x43, + 0x31, 0x32, 0x2E, 0x43, 0x31, 0x33, 0x2E, 0x43, + 0x31, 0x34, 0x2E, 0x43, 0x31, 0x35, 0x2E, 0x43, + 0x31, 0x36, 0x2E, 0x43, 0x31, 0x37, 0x2E, 0x43, + // Bytes 1cc0 - 1cff + 0x31, 0x38, 0x2E, 0x43, 0x31, 0x39, 0x2E, 0x43, + 0x32, 0x30, 0x2E, 0x43, 0x3A, 0x3A, 0x3D, 0x43, + 0x3D, 0x3D, 0x3D, 0x43, 0x43, 0x6F, 0x2E, 0x43, + 0x46, 0x41, 0x58, 0x43, 0x47, 0x48, 0x7A, 0x43, + 0x47, 0x50, 0x61, 0x43, 0x49, 0x49, 0x49, 0x43, + 0x4C, 0x54, 0x44, 0x43, 0x4C, 0xC2, 0xB7, 0x43, + 0x4D, 0x48, 0x7A, 0x43, 0x4D, 0x50, 0x61, 0x43, + 0x4D, 0xCE, 0xA9, 0x43, 0x50, 0x50, 0x4D, 0x43, + // Bytes 1d00 - 1d3f + 0x50, 0x50, 0x56, 0x43, 0x50, 0x54, 0x45, 0x43, + 0x54, 0x45, 0x4C, 0x43, 0x54, 0x48, 0x7A, 0x43, + 0x56, 0x49, 0x49, 0x43, 0x58, 0x49, 0x49, 0x43, + 0x61, 0x2F, 0x63, 0x43, 0x61, 0x2F, 0x73, 0x43, + 0x61, 0xCA, 0xBE, 0x43, 0x62, 0x61, 0x72, 0x43, + 0x63, 0x2F, 0x6F, 0x43, 0x63, 0x2F, 0x75, 0x43, + 0x63, 0x61, 0x6C, 0x43, 0x63, 0x6D, 0x32, 0x43, + 0x63, 0x6D, 0x33, 0x43, 0x64, 0x6D, 0x32, 0x43, + // Bytes 1d40 - 1d7f + 0x64, 0x6D, 0x33, 0x43, 0x65, 0x72, 0x67, 0x43, + 0x66, 0x66, 0x69, 0x43, 0x66, 0x66, 0x6C, 0x43, + 0x67, 0x61, 0x6C, 0x43, 0x68, 0x50, 0x61, 0x43, + 0x69, 0x69, 0x69, 0x43, 0x6B, 0x48, 0x7A, 0x43, + 0x6B, 0x50, 0x61, 0x43, 0x6B, 0x6D, 0x32, 0x43, + 0x6B, 0x6D, 0x33, 0x43, 0x6B, 0xCE, 0xA9, 0x43, + 0x6C, 0x6F, 0x67, 0x43, 0x6C, 0xC2, 0xB7, 0x43, + 0x6D, 0x69, 0x6C, 0x43, 0x6D, 0x6D, 0x32, 0x43, + // Bytes 1d80 - 1dbf + 0x6D, 0x6D, 0x33, 0x43, 0x6D, 0x6F, 0x6C, 0x43, + 0x72, 0x61, 0x64, 0x43, 0x76, 0x69, 0x69, 0x43, + 0x78, 0x69, 0x69, 0x43, 0xC2, 0xB0, 0x43, 0x43, + 0xC2, 0xB0, 0x46, 0x43, 0xCA, 0xBC, 0x6E, 0x43, + 0xCE, 0xBC, 0x41, 0x43, 0xCE, 0xBC, 0x46, 0x43, + 0xCE, 0xBC, 0x56, 0x43, 0xCE, 0xBC, 0x57, 0x43, + 0xCE, 0xBC, 0x67, 0x43, 0xCE, 0xBC, 0x6C, 0x43, + 0xCE, 0xBC, 0x6D, 0x43, 0xCE, 0xBC, 0x73, 0x44, + // Bytes 1dc0 - 1dff + 0x28, 0x31, 0x30, 0x29, 0x44, 0x28, 0x31, 0x31, + 0x29, 0x44, 0x28, 0x31, 0x32, 0x29, 0x44, 0x28, + 0x31, 0x33, 0x29, 0x44, 0x28, 0x31, 0x34, 0x29, + 0x44, 0x28, 0x31, 0x35, 0x29, 0x44, 0x28, 0x31, + 0x36, 0x29, 0x44, 0x28, 0x31, 0x37, 0x29, 0x44, + 0x28, 0x31, 0x38, 0x29, 0x44, 0x28, 0x31, 0x39, + 0x29, 0x44, 0x28, 0x32, 0x30, 0x29, 0x44, 0x30, + 0xE7, 0x82, 0xB9, 0x44, 0x31, 0xE2, 0x81, 0x84, + // Bytes 1e00 - 1e3f + 0x44, 0x31, 0xE6, 0x97, 0xA5, 0x44, 0x31, 0xE6, + 0x9C, 0x88, 0x44, 0x31, 0xE7, 0x82, 0xB9, 0x44, + 0x32, 0xE6, 0x97, 0xA5, 0x44, 0x32, 0xE6, 0x9C, + 0x88, 0x44, 0x32, 0xE7, 0x82, 0xB9, 0x44, 0x33, + 0xE6, 0x97, 0xA5, 0x44, 0x33, 0xE6, 0x9C, 0x88, + 0x44, 0x33, 0xE7, 0x82, 0xB9, 0x44, 0x34, 0xE6, + 0x97, 0xA5, 0x44, 0x34, 0xE6, 0x9C, 0x88, 0x44, + 0x34, 0xE7, 0x82, 0xB9, 0x44, 0x35, 0xE6, 0x97, + // Bytes 1e40 - 1e7f + 0xA5, 0x44, 0x35, 0xE6, 0x9C, 0x88, 0x44, 0x35, + 0xE7, 0x82, 0xB9, 0x44, 0x36, 0xE6, 0x97, 0xA5, + 0x44, 0x36, 0xE6, 0x9C, 0x88, 0x44, 0x36, 0xE7, + 0x82, 0xB9, 0x44, 0x37, 0xE6, 0x97, 0xA5, 0x44, + 0x37, 0xE6, 0x9C, 0x88, 0x44, 0x37, 0xE7, 0x82, + 0xB9, 0x44, 0x38, 0xE6, 0x97, 0xA5, 0x44, 0x38, + 0xE6, 0x9C, 0x88, 0x44, 0x38, 0xE7, 0x82, 0xB9, + 0x44, 0x39, 0xE6, 0x97, 0xA5, 0x44, 0x39, 0xE6, + // Bytes 1e80 - 1ebf + 0x9C, 0x88, 0x44, 0x39, 0xE7, 0x82, 0xB9, 0x44, + 0x56, 0x49, 0x49, 0x49, 0x44, 0x61, 0x2E, 0x6D, + 0x2E, 0x44, 0x6B, 0x63, 0x61, 0x6C, 0x44, 0x70, + 0x2E, 0x6D, 0x2E, 0x44, 0x76, 0x69, 0x69, 0x69, + 0x44, 0xD5, 0xA5, 0xD6, 0x82, 0x44, 0xD5, 0xB4, + 0xD5, 0xA5, 0x44, 0xD5, 0xB4, 0xD5, 0xAB, 0x44, + 0xD5, 0xB4, 0xD5, 0xAD, 0x44, 0xD5, 0xB4, 0xD5, + 0xB6, 0x44, 0xD5, 0xBE, 0xD5, 0xB6, 0x44, 0xD7, + // Bytes 1ec0 - 1eff + 0x90, 0xD7, 0x9C, 0x44, 0xD8, 0xA7, 0xD9, 0xB4, + 0x44, 0xD8, 0xA8, 0xD8, 0xAC, 0x44, 0xD8, 0xA8, + 0xD8, 0xAD, 0x44, 0xD8, 0xA8, 0xD8, 0xAE, 0x44, + 0xD8, 0xA8, 0xD8, 0xB1, 0x44, 0xD8, 0xA8, 0xD8, + 0xB2, 0x44, 0xD8, 0xA8, 0xD9, 0x85, 0x44, 0xD8, + 0xA8, 0xD9, 0x86, 0x44, 0xD8, 0xA8, 0xD9, 0x87, + 0x44, 0xD8, 0xA8, 0xD9, 0x89, 0x44, 0xD8, 0xA8, + 0xD9, 0x8A, 0x44, 0xD8, 0xAA, 0xD8, 0xAC, 0x44, + // Bytes 1f00 - 1f3f + 0xD8, 0xAA, 0xD8, 0xAD, 0x44, 0xD8, 0xAA, 0xD8, + 0xAE, 0x44, 0xD8, 0xAA, 0xD8, 0xB1, 0x44, 0xD8, + 0xAA, 0xD8, 0xB2, 0x44, 0xD8, 0xAA, 0xD9, 0x85, + 0x44, 0xD8, 0xAA, 0xD9, 0x86, 0x44, 0xD8, 0xAA, + 0xD9, 0x87, 0x44, 0xD8, 0xAA, 0xD9, 0x89, 0x44, + 0xD8, 0xAA, 0xD9, 0x8A, 0x44, 0xD8, 0xAB, 0xD8, + 0xAC, 0x44, 0xD8, 0xAB, 0xD8, 0xB1, 0x44, 0xD8, + 0xAB, 0xD8, 0xB2, 0x44, 0xD8, 0xAB, 0xD9, 0x85, + // Bytes 1f40 - 1f7f + 0x44, 0xD8, 0xAB, 0xD9, 0x86, 0x44, 0xD8, 0xAB, + 0xD9, 0x87, 0x44, 0xD8, 0xAB, 0xD9, 0x89, 0x44, + 0xD8, 0xAB, 0xD9, 0x8A, 0x44, 0xD8, 0xAC, 0xD8, + 0xAD, 0x44, 0xD8, 0xAC, 0xD9, 0x85, 0x44, 0xD8, + 0xAC, 0xD9, 0x89, 0x44, 0xD8, 0xAC, 0xD9, 0x8A, + 0x44, 0xD8, 0xAD, 0xD8, 0xAC, 0x44, 0xD8, 0xAD, + 0xD9, 0x85, 0x44, 0xD8, 0xAD, 0xD9, 0x89, 0x44, + 0xD8, 0xAD, 0xD9, 0x8A, 0x44, 0xD8, 0xAE, 0xD8, + // Bytes 1f80 - 1fbf + 0xAC, 0x44, 0xD8, 0xAE, 0xD8, 0xAD, 0x44, 0xD8, + 0xAE, 0xD9, 0x85, 0x44, 0xD8, 0xAE, 0xD9, 0x89, + 0x44, 0xD8, 0xAE, 0xD9, 0x8A, 0x44, 0xD8, 0xB3, + 0xD8, 0xAC, 0x44, 0xD8, 0xB3, 0xD8, 0xAD, 0x44, + 0xD8, 0xB3, 0xD8, 0xAE, 0x44, 0xD8, 0xB3, 0xD8, + 0xB1, 0x44, 0xD8, 0xB3, 0xD9, 0x85, 0x44, 0xD8, + 0xB3, 0xD9, 0x87, 0x44, 0xD8, 0xB3, 0xD9, 0x89, + 0x44, 0xD8, 0xB3, 0xD9, 0x8A, 0x44, 0xD8, 0xB4, + // Bytes 1fc0 - 1fff + 0xD8, 0xAC, 0x44, 0xD8, 0xB4, 0xD8, 0xAD, 0x44, + 0xD8, 0xB4, 0xD8, 0xAE, 0x44, 0xD8, 0xB4, 0xD8, + 0xB1, 0x44, 0xD8, 0xB4, 0xD9, 0x85, 0x44, 0xD8, + 0xB4, 0xD9, 0x87, 0x44, 0xD8, 0xB4, 0xD9, 0x89, + 0x44, 0xD8, 0xB4, 0xD9, 0x8A, 0x44, 0xD8, 0xB5, + 0xD8, 0xAD, 0x44, 0xD8, 0xB5, 0xD8, 0xAE, 0x44, + 0xD8, 0xB5, 0xD8, 0xB1, 0x44, 0xD8, 0xB5, 0xD9, + 0x85, 0x44, 0xD8, 0xB5, 0xD9, 0x89, 0x44, 0xD8, + // Bytes 2000 - 203f + 0xB5, 0xD9, 0x8A, 0x44, 0xD8, 0xB6, 0xD8, 0xAC, + 0x44, 0xD8, 0xB6, 0xD8, 0xAD, 0x44, 0xD8, 0xB6, + 0xD8, 0xAE, 0x44, 0xD8, 0xB6, 0xD8, 0xB1, 0x44, + 0xD8, 0xB6, 0xD9, 0x85, 0x44, 0xD8, 0xB6, 0xD9, + 0x89, 0x44, 0xD8, 0xB6, 0xD9, 0x8A, 0x44, 0xD8, + 0xB7, 0xD8, 0xAD, 0x44, 0xD8, 0xB7, 0xD9, 0x85, + 0x44, 0xD8, 0xB7, 0xD9, 0x89, 0x44, 0xD8, 0xB7, + 0xD9, 0x8A, 0x44, 0xD8, 0xB8, 0xD9, 0x85, 0x44, + // Bytes 2040 - 207f + 0xD8, 0xB9, 0xD8, 0xAC, 0x44, 0xD8, 0xB9, 0xD9, + 0x85, 0x44, 0xD8, 0xB9, 0xD9, 0x89, 0x44, 0xD8, + 0xB9, 0xD9, 0x8A, 0x44, 0xD8, 0xBA, 0xD8, 0xAC, + 0x44, 0xD8, 0xBA, 0xD9, 0x85, 0x44, 0xD8, 0xBA, + 0xD9, 0x89, 0x44, 0xD8, 0xBA, 0xD9, 0x8A, 0x44, + 0xD9, 0x81, 0xD8, 0xAC, 0x44, 0xD9, 0x81, 0xD8, + 0xAD, 0x44, 0xD9, 0x81, 0xD8, 0xAE, 0x44, 0xD9, + 0x81, 0xD9, 0x85, 0x44, 0xD9, 0x81, 0xD9, 0x89, + // Bytes 2080 - 20bf + 0x44, 0xD9, 0x81, 0xD9, 0x8A, 0x44, 0xD9, 0x82, + 0xD8, 0xAD, 0x44, 0xD9, 0x82, 0xD9, 0x85, 0x44, + 0xD9, 0x82, 0xD9, 0x89, 0x44, 0xD9, 0x82, 0xD9, + 0x8A, 0x44, 0xD9, 0x83, 0xD8, 0xA7, 0x44, 0xD9, + 0x83, 0xD8, 0xAC, 0x44, 0xD9, 0x83, 0xD8, 0xAD, + 0x44, 0xD9, 0x83, 0xD8, 0xAE, 0x44, 0xD9, 0x83, + 0xD9, 0x84, 0x44, 0xD9, 0x83, 0xD9, 0x85, 0x44, + 0xD9, 0x83, 0xD9, 0x89, 0x44, 0xD9, 0x83, 0xD9, + // Bytes 20c0 - 20ff + 0x8A, 0x44, 0xD9, 0x84, 0xD8, 0xA7, 0x44, 0xD9, + 0x84, 0xD8, 0xAC, 0x44, 0xD9, 0x84, 0xD8, 0xAD, + 0x44, 0xD9, 0x84, 0xD8, 0xAE, 0x44, 0xD9, 0x84, + 0xD9, 0x85, 0x44, 0xD9, 0x84, 0xD9, 0x87, 0x44, + 0xD9, 0x84, 0xD9, 0x89, 0x44, 0xD9, 0x84, 0xD9, + 0x8A, 0x44, 0xD9, 0x85, 0xD8, 0xA7, 0x44, 0xD9, + 0x85, 0xD8, 0xAC, 0x44, 0xD9, 0x85, 0xD8, 0xAD, + 0x44, 0xD9, 0x85, 0xD8, 0xAE, 0x44, 0xD9, 0x85, + // Bytes 2100 - 213f + 0xD9, 0x85, 0x44, 0xD9, 0x85, 0xD9, 0x89, 0x44, + 0xD9, 0x85, 0xD9, 0x8A, 0x44, 0xD9, 0x86, 0xD8, + 0xAC, 0x44, 0xD9, 0x86, 0xD8, 0xAD, 0x44, 0xD9, + 0x86, 0xD8, 0xAE, 0x44, 0xD9, 0x86, 0xD8, 0xB1, + 0x44, 0xD9, 0x86, 0xD8, 0xB2, 0x44, 0xD9, 0x86, + 0xD9, 0x85, 0x44, 0xD9, 0x86, 0xD9, 0x86, 0x44, + 0xD9, 0x86, 0xD9, 0x87, 0x44, 0xD9, 0x86, 0xD9, + 0x89, 0x44, 0xD9, 0x86, 0xD9, 0x8A, 0x44, 0xD9, + // Bytes 2140 - 217f + 0x87, 0xD8, 0xAC, 0x44, 0xD9, 0x87, 0xD9, 0x85, + 0x44, 0xD9, 0x87, 0xD9, 0x89, 0x44, 0xD9, 0x87, + 0xD9, 0x8A, 0x44, 0xD9, 0x88, 0xD9, 0xB4, 0x44, + 0xD9, 0x8A, 0xD8, 0xAC, 0x44, 0xD9, 0x8A, 0xD8, + 0xAD, 0x44, 0xD9, 0x8A, 0xD8, 0xAE, 0x44, 0xD9, + 0x8A, 0xD8, 0xB1, 0x44, 0xD9, 0x8A, 0xD8, 0xB2, + 0x44, 0xD9, 0x8A, 0xD9, 0x85, 0x44, 0xD9, 0x8A, + 0xD9, 0x86, 0x44, 0xD9, 0x8A, 0xD9, 0x87, 0x44, + // Bytes 2180 - 21bf + 0xD9, 0x8A, 0xD9, 0x89, 0x44, 0xD9, 0x8A, 0xD9, + 0x8A, 0x44, 0xD9, 0x8A, 0xD9, 0xB4, 0x44, 0xDB, + 0x87, 0xD9, 0xB4, 0x45, 0x28, 0xE1, 0x84, 0x80, + 0x29, 0x45, 0x28, 0xE1, 0x84, 0x82, 0x29, 0x45, + 0x28, 0xE1, 0x84, 0x83, 0x29, 0x45, 0x28, 0xE1, + 0x84, 0x85, 0x29, 0x45, 0x28, 0xE1, 0x84, 0x86, + 0x29, 0x45, 0x28, 0xE1, 0x84, 0x87, 0x29, 0x45, + 0x28, 0xE1, 0x84, 0x89, 0x29, 0x45, 0x28, 0xE1, + // Bytes 21c0 - 21ff + 0x84, 0x8B, 0x29, 0x45, 0x28, 0xE1, 0x84, 0x8C, + 0x29, 0x45, 0x28, 0xE1, 0x84, 0x8E, 0x29, 0x45, + 0x28, 0xE1, 0x84, 0x8F, 0x29, 0x45, 0x28, 0xE1, + 0x84, 0x90, 0x29, 0x45, 0x28, 0xE1, 0x84, 0x91, + 0x29, 0x45, 0x28, 0xE1, 0x84, 0x92, 0x29, 0x45, + 0x28, 0xE4, 0xB8, 0x80, 0x29, 0x45, 0x28, 0xE4, + 0xB8, 0x83, 0x29, 0x45, 0x28, 0xE4, 0xB8, 0x89, + 0x29, 0x45, 0x28, 0xE4, 0xB9, 0x9D, 0x29, 0x45, + // Bytes 2200 - 223f + 0x28, 0xE4, 0xBA, 0x8C, 0x29, 0x45, 0x28, 0xE4, + 0xBA, 0x94, 0x29, 0x45, 0x28, 0xE4, 0xBB, 0xA3, + 0x29, 0x45, 0x28, 0xE4, 0xBC, 0x81, 0x29, 0x45, + 0x28, 0xE4, 0xBC, 0x91, 0x29, 0x45, 0x28, 0xE5, + 0x85, 0xAB, 0x29, 0x45, 0x28, 0xE5, 0x85, 0xAD, + 0x29, 0x45, 0x28, 0xE5, 0x8A, 0xB4, 0x29, 0x45, + 0x28, 0xE5, 0x8D, 0x81, 0x29, 0x45, 0x28, 0xE5, + 0x8D, 0x94, 0x29, 0x45, 0x28, 0xE5, 0x90, 0x8D, + // Bytes 2240 - 227f + 0x29, 0x45, 0x28, 0xE5, 0x91, 0xBC, 0x29, 0x45, + 0x28, 0xE5, 0x9B, 0x9B, 0x29, 0x45, 0x28, 0xE5, + 0x9C, 0x9F, 0x29, 0x45, 0x28, 0xE5, 0xAD, 0xA6, + 0x29, 0x45, 0x28, 0xE6, 0x97, 0xA5, 0x29, 0x45, + 0x28, 0xE6, 0x9C, 0x88, 0x29, 0x45, 0x28, 0xE6, + 0x9C, 0x89, 0x29, 0x45, 0x28, 0xE6, 0x9C, 0xA8, + 0x29, 0x45, 0x28, 0xE6, 0xA0, 0xAA, 0x29, 0x45, + 0x28, 0xE6, 0xB0, 0xB4, 0x29, 0x45, 0x28, 0xE7, + // Bytes 2280 - 22bf + 0x81, 0xAB, 0x29, 0x45, 0x28, 0xE7, 0x89, 0xB9, + 0x29, 0x45, 0x28, 0xE7, 0x9B, 0xA3, 0x29, 0x45, + 0x28, 0xE7, 0xA4, 0xBE, 0x29, 0x45, 0x28, 0xE7, + 0xA5, 0x9D, 0x29, 0x45, 0x28, 0xE7, 0xA5, 0xAD, + 0x29, 0x45, 0x28, 0xE8, 0x87, 0xAA, 0x29, 0x45, + 0x28, 0xE8, 0x87, 0xB3, 0x29, 0x45, 0x28, 0xE8, + 0xB2, 0xA1, 0x29, 0x45, 0x28, 0xE8, 0xB3, 0x87, + 0x29, 0x45, 0x28, 0xE9, 0x87, 0x91, 0x29, 0x45, + // Bytes 22c0 - 22ff + 0x30, 0xE2, 0x81, 0x84, 0x33, 0x45, 0x31, 0x30, + 0xE6, 0x97, 0xA5, 0x45, 0x31, 0x30, 0xE6, 0x9C, + 0x88, 0x45, 0x31, 0x30, 0xE7, 0x82, 0xB9, 0x45, + 0x31, 0x31, 0xE6, 0x97, 0xA5, 0x45, 0x31, 0x31, + 0xE6, 0x9C, 0x88, 0x45, 0x31, 0x31, 0xE7, 0x82, + 0xB9, 0x45, 0x31, 0x32, 0xE6, 0x97, 0xA5, 0x45, + 0x31, 0x32, 0xE6, 0x9C, 0x88, 0x45, 0x31, 0x32, + 0xE7, 0x82, 0xB9, 0x45, 0x31, 0x33, 0xE6, 0x97, + // Bytes 2300 - 233f + 0xA5, 0x45, 0x31, 0x33, 0xE7, 0x82, 0xB9, 0x45, + 0x31, 0x34, 0xE6, 0x97, 0xA5, 0x45, 0x31, 0x34, + 0xE7, 0x82, 0xB9, 0x45, 0x31, 0x35, 0xE6, 0x97, + 0xA5, 0x45, 0x31, 0x35, 0xE7, 0x82, 0xB9, 0x45, + 0x31, 0x36, 0xE6, 0x97, 0xA5, 0x45, 0x31, 0x36, + 0xE7, 0x82, 0xB9, 0x45, 0x31, 0x37, 0xE6, 0x97, + 0xA5, 0x45, 0x31, 0x37, 0xE7, 0x82, 0xB9, 0x45, + 0x31, 0x38, 0xE6, 0x97, 0xA5, 0x45, 0x31, 0x38, + // Bytes 2340 - 237f + 0xE7, 0x82, 0xB9, 0x45, 0x31, 0x39, 0xE6, 0x97, + 0xA5, 0x45, 0x31, 0x39, 0xE7, 0x82, 0xB9, 0x45, + 0x31, 0xE2, 0x81, 0x84, 0x32, 0x45, 0x31, 0xE2, + 0x81, 0x84, 0x33, 0x45, 0x31, 0xE2, 0x81, 0x84, + 0x34, 0x45, 0x31, 0xE2, 0x81, 0x84, 0x35, 0x45, + 0x31, 0xE2, 0x81, 0x84, 0x36, 0x45, 0x31, 0xE2, + 0x81, 0x84, 0x37, 0x45, 0x31, 0xE2, 0x81, 0x84, + 0x38, 0x45, 0x31, 0xE2, 0x81, 0x84, 0x39, 0x45, + // Bytes 2380 - 23bf + 0x32, 0x30, 0xE6, 0x97, 0xA5, 0x45, 0x32, 0x30, + 0xE7, 0x82, 0xB9, 0x45, 0x32, 0x31, 0xE6, 0x97, + 0xA5, 0x45, 0x32, 0x31, 0xE7, 0x82, 0xB9, 0x45, + 0x32, 0x32, 0xE6, 0x97, 0xA5, 0x45, 0x32, 0x32, + 0xE7, 0x82, 0xB9, 0x45, 0x32, 0x33, 0xE6, 0x97, + 0xA5, 0x45, 0x32, 0x33, 0xE7, 0x82, 0xB9, 0x45, + 0x32, 0x34, 0xE6, 0x97, 0xA5, 0x45, 0x32, 0x34, + 0xE7, 0x82, 0xB9, 0x45, 0x32, 0x35, 0xE6, 0x97, + // Bytes 23c0 - 23ff + 0xA5, 0x45, 0x32, 0x36, 0xE6, 0x97, 0xA5, 0x45, + 0x32, 0x37, 0xE6, 0x97, 0xA5, 0x45, 0x32, 0x38, + 0xE6, 0x97, 0xA5, 0x45, 0x32, 0x39, 0xE6, 0x97, + 0xA5, 0x45, 0x32, 0xE2, 0x81, 0x84, 0x33, 0x45, + 0x32, 0xE2, 0x81, 0x84, 0x35, 0x45, 0x33, 0x30, + 0xE6, 0x97, 0xA5, 0x45, 0x33, 0x31, 0xE6, 0x97, + 0xA5, 0x45, 0x33, 0xE2, 0x81, 0x84, 0x34, 0x45, + 0x33, 0xE2, 0x81, 0x84, 0x35, 0x45, 0x33, 0xE2, + // Bytes 2400 - 243f + 0x81, 0x84, 0x38, 0x45, 0x34, 0xE2, 0x81, 0x84, + 0x35, 0x45, 0x35, 0xE2, 0x81, 0x84, 0x36, 0x45, + 0x35, 0xE2, 0x81, 0x84, 0x38, 0x45, 0x37, 0xE2, + 0x81, 0x84, 0x38, 0x45, 0x41, 0xE2, 0x88, 0x95, + 0x6D, 0x45, 0x56, 0xE2, 0x88, 0x95, 0x6D, 0x45, + 0x6D, 0xE2, 0x88, 0x95, 0x73, 0x46, 0x31, 0xE2, + 0x81, 0x84, 0x31, 0x30, 0x46, 0x43, 0xE2, 0x88, + 0x95, 0x6B, 0x67, 0x46, 0x6D, 0xE2, 0x88, 0x95, + // Bytes 2440 - 247f + 0x73, 0x32, 0x46, 0xD8, 0xA8, 0xD8, 0xAD, 0xD9, + 0x8A, 0x46, 0xD8, 0xA8, 0xD8, 0xAE, 0xD9, 0x8A, + 0x46, 0xD8, 0xAA, 0xD8, 0xAC, 0xD9, 0x85, 0x46, + 0xD8, 0xAA, 0xD8, 0xAC, 0xD9, 0x89, 0x46, 0xD8, + 0xAA, 0xD8, 0xAC, 0xD9, 0x8A, 0x46, 0xD8, 0xAA, + 0xD8, 0xAD, 0xD8, 0xAC, 0x46, 0xD8, 0xAA, 0xD8, + 0xAD, 0xD9, 0x85, 0x46, 0xD8, 0xAA, 0xD8, 0xAE, + 0xD9, 0x85, 0x46, 0xD8, 0xAA, 0xD8, 0xAE, 0xD9, + // Bytes 2480 - 24bf + 0x89, 0x46, 0xD8, 0xAA, 0xD8, 0xAE, 0xD9, 0x8A, + 0x46, 0xD8, 0xAA, 0xD9, 0x85, 0xD8, 0xAC, 0x46, + 0xD8, 0xAA, 0xD9, 0x85, 0xD8, 0xAD, 0x46, 0xD8, + 0xAA, 0xD9, 0x85, 0xD8, 0xAE, 0x46, 0xD8, 0xAA, + 0xD9, 0x85, 0xD9, 0x89, 0x46, 0xD8, 0xAA, 0xD9, + 0x85, 0xD9, 0x8A, 0x46, 0xD8, 0xAC, 0xD8, 0xAD, + 0xD9, 0x89, 0x46, 0xD8, 0xAC, 0xD8, 0xAD, 0xD9, + 0x8A, 0x46, 0xD8, 0xAC, 0xD9, 0x85, 0xD8, 0xAD, + // Bytes 24c0 - 24ff + 0x46, 0xD8, 0xAC, 0xD9, 0x85, 0xD9, 0x89, 0x46, + 0xD8, 0xAC, 0xD9, 0x85, 0xD9, 0x8A, 0x46, 0xD8, + 0xAD, 0xD8, 0xAC, 0xD9, 0x8A, 0x46, 0xD8, 0xAD, + 0xD9, 0x85, 0xD9, 0x89, 0x46, 0xD8, 0xAD, 0xD9, + 0x85, 0xD9, 0x8A, 0x46, 0xD8, 0xB3, 0xD8, 0xAC, + 0xD8, 0xAD, 0x46, 0xD8, 0xB3, 0xD8, 0xAC, 0xD9, + 0x89, 0x46, 0xD8, 0xB3, 0xD8, 0xAD, 0xD8, 0xAC, + 0x46, 0xD8, 0xB3, 0xD8, 0xAE, 0xD9, 0x89, 0x46, + // Bytes 2500 - 253f + 0xD8, 0xB3, 0xD8, 0xAE, 0xD9, 0x8A, 0x46, 0xD8, + 0xB3, 0xD9, 0x85, 0xD8, 0xAC, 0x46, 0xD8, 0xB3, + 0xD9, 0x85, 0xD8, 0xAD, 0x46, 0xD8, 0xB3, 0xD9, + 0x85, 0xD9, 0x85, 0x46, 0xD8, 0xB4, 0xD8, 0xAC, + 0xD9, 0x8A, 0x46, 0xD8, 0xB4, 0xD8, 0xAD, 0xD9, + 0x85, 0x46, 0xD8, 0xB4, 0xD8, 0xAD, 0xD9, 0x8A, + 0x46, 0xD8, 0xB4, 0xD9, 0x85, 0xD8, 0xAE, 0x46, + 0xD8, 0xB4, 0xD9, 0x85, 0xD9, 0x85, 0x46, 0xD8, + // Bytes 2540 - 257f + 0xB5, 0xD8, 0xAD, 0xD8, 0xAD, 0x46, 0xD8, 0xB5, + 0xD8, 0xAD, 0xD9, 0x8A, 0x46, 0xD8, 0xB5, 0xD9, + 0x84, 0xD9, 0x89, 0x46, 0xD8, 0xB5, 0xD9, 0x84, + 0xDB, 0x92, 0x46, 0xD8, 0xB5, 0xD9, 0x85, 0xD9, + 0x85, 0x46, 0xD8, 0xB6, 0xD8, 0xAD, 0xD9, 0x89, + 0x46, 0xD8, 0xB6, 0xD8, 0xAD, 0xD9, 0x8A, 0x46, + 0xD8, 0xB6, 0xD8, 0xAE, 0xD9, 0x85, 0x46, 0xD8, + 0xB7, 0xD9, 0x85, 0xD8, 0xAD, 0x46, 0xD8, 0xB7, + // Bytes 2580 - 25bf + 0xD9, 0x85, 0xD9, 0x85, 0x46, 0xD8, 0xB7, 0xD9, + 0x85, 0xD9, 0x8A, 0x46, 0xD8, 0xB9, 0xD8, 0xAC, + 0xD9, 0x85, 0x46, 0xD8, 0xB9, 0xD9, 0x85, 0xD9, + 0x85, 0x46, 0xD8, 0xB9, 0xD9, 0x85, 0xD9, 0x89, + 0x46, 0xD8, 0xB9, 0xD9, 0x85, 0xD9, 0x8A, 0x46, + 0xD8, 0xBA, 0xD9, 0x85, 0xD9, 0x85, 0x46, 0xD8, + 0xBA, 0xD9, 0x85, 0xD9, 0x89, 0x46, 0xD8, 0xBA, + 0xD9, 0x85, 0xD9, 0x8A, 0x46, 0xD9, 0x81, 0xD8, + // Bytes 25c0 - 25ff + 0xAE, 0xD9, 0x85, 0x46, 0xD9, 0x81, 0xD9, 0x85, + 0xD9, 0x8A, 0x46, 0xD9, 0x82, 0xD9, 0x84, 0xDB, + 0x92, 0x46, 0xD9, 0x82, 0xD9, 0x85, 0xD8, 0xAD, + 0x46, 0xD9, 0x82, 0xD9, 0x85, 0xD9, 0x85, 0x46, + 0xD9, 0x82, 0xD9, 0x85, 0xD9, 0x8A, 0x46, 0xD9, + 0x83, 0xD9, 0x85, 0xD9, 0x85, 0x46, 0xD9, 0x83, + 0xD9, 0x85, 0xD9, 0x8A, 0x46, 0xD9, 0x84, 0xD8, + 0xAC, 0xD8, 0xAC, 0x46, 0xD9, 0x84, 0xD8, 0xAC, + // Bytes 2600 - 263f + 0xD9, 0x85, 0x46, 0xD9, 0x84, 0xD8, 0xAC, 0xD9, + 0x8A, 0x46, 0xD9, 0x84, 0xD8, 0xAD, 0xD9, 0x85, + 0x46, 0xD9, 0x84, 0xD8, 0xAD, 0xD9, 0x89, 0x46, + 0xD9, 0x84, 0xD8, 0xAD, 0xD9, 0x8A, 0x46, 0xD9, + 0x84, 0xD8, 0xAE, 0xD9, 0x85, 0x46, 0xD9, 0x84, + 0xD9, 0x85, 0xD8, 0xAD, 0x46, 0xD9, 0x84, 0xD9, + 0x85, 0xD9, 0x8A, 0x46, 0xD9, 0x85, 0xD8, 0xAC, + 0xD8, 0xAD, 0x46, 0xD9, 0x85, 0xD8, 0xAC, 0xD8, + // Bytes 2640 - 267f + 0xAE, 0x46, 0xD9, 0x85, 0xD8, 0xAC, 0xD9, 0x85, + 0x46, 0xD9, 0x85, 0xD8, 0xAC, 0xD9, 0x8A, 0x46, + 0xD9, 0x85, 0xD8, 0xAD, 0xD8, 0xAC, 0x46, 0xD9, + 0x85, 0xD8, 0xAD, 0xD9, 0x85, 0x46, 0xD9, 0x85, + 0xD8, 0xAD, 0xD9, 0x8A, 0x46, 0xD9, 0x85, 0xD8, + 0xAE, 0xD8, 0xAC, 0x46, 0xD9, 0x85, 0xD8, 0xAE, + 0xD9, 0x85, 0x46, 0xD9, 0x85, 0xD8, 0xAE, 0xD9, + 0x8A, 0x46, 0xD9, 0x85, 0xD9, 0x85, 0xD9, 0x8A, + // Bytes 2680 - 26bf + 0x46, 0xD9, 0x86, 0xD8, 0xAC, 0xD8, 0xAD, 0x46, + 0xD9, 0x86, 0xD8, 0xAC, 0xD9, 0x85, 0x46, 0xD9, + 0x86, 0xD8, 0xAC, 0xD9, 0x89, 0x46, 0xD9, 0x86, + 0xD8, 0xAC, 0xD9, 0x8A, 0x46, 0xD9, 0x86, 0xD8, + 0xAD, 0xD9, 0x85, 0x46, 0xD9, 0x86, 0xD8, 0xAD, + 0xD9, 0x89, 0x46, 0xD9, 0x86, 0xD8, 0xAD, 0xD9, + 0x8A, 0x46, 0xD9, 0x86, 0xD9, 0x85, 0xD9, 0x89, + 0x46, 0xD9, 0x86, 0xD9, 0x85, 0xD9, 0x8A, 0x46, + // Bytes 26c0 - 26ff + 0xD9, 0x87, 0xD9, 0x85, 0xD8, 0xAC, 0x46, 0xD9, + 0x87, 0xD9, 0x85, 0xD9, 0x85, 0x46, 0xD9, 0x8A, + 0xD8, 0xAC, 0xD9, 0x8A, 0x46, 0xD9, 0x8A, 0xD8, + 0xAD, 0xD9, 0x8A, 0x46, 0xD9, 0x8A, 0xD9, 0x85, + 0xD9, 0x85, 0x46, 0xD9, 0x8A, 0xD9, 0x85, 0xD9, + 0x8A, 0x46, 0xD9, 0x8A, 0xD9, 0x94, 0xD8, 0xA7, + 0x46, 0xD9, 0x8A, 0xD9, 0x94, 0xD8, 0xAC, 0x46, + 0xD9, 0x8A, 0xD9, 0x94, 0xD8, 0xAD, 0x46, 0xD9, + // Bytes 2700 - 273f + 0x8A, 0xD9, 0x94, 0xD8, 0xAE, 0x46, 0xD9, 0x8A, + 0xD9, 0x94, 0xD8, 0xB1, 0x46, 0xD9, 0x8A, 0xD9, + 0x94, 0xD8, 0xB2, 0x46, 0xD9, 0x8A, 0xD9, 0x94, + 0xD9, 0x85, 0x46, 0xD9, 0x8A, 0xD9, 0x94, 0xD9, + 0x86, 0x46, 0xD9, 0x8A, 0xD9, 0x94, 0xD9, 0x87, + 0x46, 0xD9, 0x8A, 0xD9, 0x94, 0xD9, 0x88, 0x46, + 0xD9, 0x8A, 0xD9, 0x94, 0xD9, 0x89, 0x46, 0xD9, + 0x8A, 0xD9, 0x94, 0xD9, 0x8A, 0x46, 0xD9, 0x8A, + // Bytes 2740 - 277f + 0xD9, 0x94, 0xDB, 0x86, 0x46, 0xD9, 0x8A, 0xD9, + 0x94, 0xDB, 0x87, 0x46, 0xD9, 0x8A, 0xD9, 0x94, + 0xDB, 0x88, 0x46, 0xD9, 0x8A, 0xD9, 0x94, 0xDB, + 0x90, 0x46, 0xD9, 0x8A, 0xD9, 0x94, 0xDB, 0x95, + 0x46, 0xE0, 0xB9, 0x8D, 0xE0, 0xB8, 0xB2, 0x46, + 0xE0, 0xBA, 0xAB, 0xE0, 0xBA, 0x99, 0x46, 0xE0, + 0xBA, 0xAB, 0xE0, 0xBA, 0xA1, 0x46, 0xE0, 0xBB, + 0x8D, 0xE0, 0xBA, 0xB2, 0x46, 0xE0, 0xBD, 0x80, + // Bytes 2780 - 27bf + 0xE0, 0xBE, 0xB5, 0x46, 0xE0, 0xBD, 0x82, 0xE0, + 0xBE, 0xB7, 0x46, 0xE0, 0xBD, 0x8C, 0xE0, 0xBE, + 0xB7, 0x46, 0xE0, 0xBD, 0x91, 0xE0, 0xBE, 0xB7, + 0x46, 0xE0, 0xBD, 0x96, 0xE0, 0xBE, 0xB7, 0x46, + 0xE0, 0xBD, 0x9B, 0xE0, 0xBE, 0xB7, 0x46, 0xE0, + 0xBE, 0x90, 0xE0, 0xBE, 0xB5, 0x46, 0xE0, 0xBE, + 0x92, 0xE0, 0xBE, 0xB7, 0x46, 0xE0, 0xBE, 0x9C, + 0xE0, 0xBE, 0xB7, 0x46, 0xE0, 0xBE, 0xA1, 0xE0, + // Bytes 27c0 - 27ff + 0xBE, 0xB7, 0x46, 0xE0, 0xBE, 0xA6, 0xE0, 0xBE, + 0xB7, 0x46, 0xE0, 0xBE, 0xAB, 0xE0, 0xBE, 0xB7, + 0x46, 0xE1, 0x84, 0x80, 0xE1, 0x85, 0xA1, 0x46, + 0xE1, 0x84, 0x82, 0xE1, 0x85, 0xA1, 0x46, 0xE1, + 0x84, 0x83, 0xE1, 0x85, 0xA1, 0x46, 0xE1, 0x84, + 0x85, 0xE1, 0x85, 0xA1, 0x46, 0xE1, 0x84, 0x86, + 0xE1, 0x85, 0xA1, 0x46, 0xE1, 0x84, 0x87, 0xE1, + 0x85, 0xA1, 0x46, 0xE1, 0x84, 0x89, 0xE1, 0x85, + // Bytes 2800 - 283f + 0xA1, 0x46, 0xE1, 0x84, 0x8B, 0xE1, 0x85, 0xA1, + 0x46, 0xE1, 0x84, 0x8B, 0xE1, 0x85, 0xAE, 0x46, + 0xE1, 0x84, 0x8C, 0xE1, 0x85, 0xA1, 0x46, 0xE1, + 0x84, 0x8E, 0xE1, 0x85, 0xA1, 0x46, 0xE1, 0x84, + 0x8F, 0xE1, 0x85, 0xA1, 0x46, 0xE1, 0x84, 0x90, + 0xE1, 0x85, 0xA1, 0x46, 0xE1, 0x84, 0x91, 0xE1, + 0x85, 0xA1, 0x46, 0xE1, 0x84, 0x92, 0xE1, 0x85, + 0xA1, 0x46, 0xE2, 0x80, 0xB2, 0xE2, 0x80, 0xB2, + // Bytes 2840 - 287f + 0x46, 0xE2, 0x80, 0xB5, 0xE2, 0x80, 0xB5, 0x46, + 0xE2, 0x88, 0xAB, 0xE2, 0x88, 0xAB, 0x46, 0xE2, + 0x88, 0xAE, 0xE2, 0x88, 0xAE, 0x46, 0xE3, 0x81, + 0xBB, 0xE3, 0x81, 0x8B, 0x46, 0xE3, 0x82, 0x88, + 0xE3, 0x82, 0x8A, 0x46, 0xE3, 0x82, 0xAD, 0xE3, + 0x83, 0xAD, 0x46, 0xE3, 0x82, 0xB3, 0xE3, 0x82, + 0xB3, 0x46, 0xE3, 0x82, 0xB3, 0xE3, 0x83, 0x88, + 0x46, 0xE3, 0x83, 0x88, 0xE3, 0x83, 0xB3, 0x46, + // Bytes 2880 - 28bf + 0xE3, 0x83, 0x8A, 0xE3, 0x83, 0x8E, 0x46, 0xE3, + 0x83, 0x9B, 0xE3, 0x83, 0xB3, 0x46, 0xE3, 0x83, + 0x9F, 0xE3, 0x83, 0xAA, 0x46, 0xE3, 0x83, 0xAA, + 0xE3, 0x83, 0xA9, 0x46, 0xE3, 0x83, 0xAC, 0xE3, + 0x83, 0xA0, 0x46, 0xE5, 0xA4, 0xA7, 0xE6, 0xAD, + 0xA3, 0x46, 0xE5, 0xB9, 0xB3, 0xE6, 0x88, 0x90, + 0x46, 0xE6, 0x98, 0x8E, 0xE6, 0xB2, 0xBB, 0x46, + 0xE6, 0x98, 0xAD, 0xE5, 0x92, 0x8C, 0x47, 0x72, + // Bytes 28c0 - 28ff + 0x61, 0x64, 0xE2, 0x88, 0x95, 0x73, 0x47, 0xE3, + 0x80, 0x94, 0x53, 0xE3, 0x80, 0x95, 0x48, 0x28, + 0xE1, 0x84, 0x80, 0xE1, 0x85, 0xA1, 0x29, 0x48, + 0x28, 0xE1, 0x84, 0x82, 0xE1, 0x85, 0xA1, 0x29, + 0x48, 0x28, 0xE1, 0x84, 0x83, 0xE1, 0x85, 0xA1, + 0x29, 0x48, 0x28, 0xE1, 0x84, 0x85, 0xE1, 0x85, + 0xA1, 0x29, 0x48, 0x28, 0xE1, 0x84, 0x86, 0xE1, + 0x85, 0xA1, 0x29, 0x48, 0x28, 0xE1, 0x84, 0x87, + // Bytes 2900 - 293f + 0xE1, 0x85, 0xA1, 0x29, 0x48, 0x28, 0xE1, 0x84, + 0x89, 0xE1, 0x85, 0xA1, 0x29, 0x48, 0x28, 0xE1, + 0x84, 0x8B, 0xE1, 0x85, 0xA1, 0x29, 0x48, 0x28, + 0xE1, 0x84, 0x8C, 0xE1, 0x85, 0xA1, 0x29, 0x48, + 0x28, 0xE1, 0x84, 0x8C, 0xE1, 0x85, 0xAE, 0x29, + 0x48, 0x28, 0xE1, 0x84, 0x8E, 0xE1, 0x85, 0xA1, + 0x29, 0x48, 0x28, 0xE1, 0x84, 0x8F, 0xE1, 0x85, + 0xA1, 0x29, 0x48, 0x28, 0xE1, 0x84, 0x90, 0xE1, + // Bytes 2940 - 297f + 0x85, 0xA1, 0x29, 0x48, 0x28, 0xE1, 0x84, 0x91, + 0xE1, 0x85, 0xA1, 0x29, 0x48, 0x28, 0xE1, 0x84, + 0x92, 0xE1, 0x85, 0xA1, 0x29, 0x48, 0x72, 0x61, + 0x64, 0xE2, 0x88, 0x95, 0x73, 0x32, 0x48, 0xD8, + 0xA7, 0xD9, 0x83, 0xD8, 0xA8, 0xD8, 0xB1, 0x48, + 0xD8, 0xA7, 0xD9, 0x84, 0xD9, 0x84, 0xD9, 0x87, + 0x48, 0xD8, 0xB1, 0xD8, 0xB3, 0xD9, 0x88, 0xD9, + 0x84, 0x48, 0xD8, 0xB1, 0xDB, 0x8C, 0xD8, 0xA7, + // Bytes 2980 - 29bf + 0xD9, 0x84, 0x48, 0xD8, 0xB5, 0xD9, 0x84, 0xD8, + 0xB9, 0xD9, 0x85, 0x48, 0xD8, 0xB9, 0xD9, 0x84, + 0xD9, 0x8A, 0xD9, 0x87, 0x48, 0xD9, 0x85, 0xD8, + 0xAD, 0xD9, 0x85, 0xD8, 0xAF, 0x48, 0xD9, 0x88, + 0xD8, 0xB3, 0xD9, 0x84, 0xD9, 0x85, 0x49, 0xE2, + 0x80, 0xB2, 0xE2, 0x80, 0xB2, 0xE2, 0x80, 0xB2, + 0x49, 0xE2, 0x80, 0xB5, 0xE2, 0x80, 0xB5, 0xE2, + 0x80, 0xB5, 0x49, 0xE2, 0x88, 0xAB, 0xE2, 0x88, + // Bytes 29c0 - 29ff + 0xAB, 0xE2, 0x88, 0xAB, 0x49, 0xE2, 0x88, 0xAE, + 0xE2, 0x88, 0xAE, 0xE2, 0x88, 0xAE, 0x49, 0xE3, + 0x80, 0x94, 0xE4, 0xB8, 0x89, 0xE3, 0x80, 0x95, + 0x49, 0xE3, 0x80, 0x94, 0xE4, 0xBA, 0x8C, 0xE3, + 0x80, 0x95, 0x49, 0xE3, 0x80, 0x94, 0xE5, 0x8B, + 0x9D, 0xE3, 0x80, 0x95, 0x49, 0xE3, 0x80, 0x94, + 0xE5, 0xAE, 0x89, 0xE3, 0x80, 0x95, 0x49, 0xE3, + 0x80, 0x94, 0xE6, 0x89, 0x93, 0xE3, 0x80, 0x95, + // Bytes 2a00 - 2a3f + 0x49, 0xE3, 0x80, 0x94, 0xE6, 0x95, 0x97, 0xE3, + 0x80, 0x95, 0x49, 0xE3, 0x80, 0x94, 0xE6, 0x9C, + 0xAC, 0xE3, 0x80, 0x95, 0x49, 0xE3, 0x80, 0x94, + 0xE7, 0x82, 0xB9, 0xE3, 0x80, 0x95, 0x49, 0xE3, + 0x80, 0x94, 0xE7, 0x9B, 0x97, 0xE3, 0x80, 0x95, + 0x49, 0xE3, 0x82, 0xA2, 0xE3, 0x83, 0xBC, 0xE3, + 0x83, 0xAB, 0x49, 0xE3, 0x82, 0xA4, 0xE3, 0x83, + 0xB3, 0xE3, 0x83, 0x81, 0x49, 0xE3, 0x82, 0xA6, + // Bytes 2a40 - 2a7f + 0xE3, 0x82, 0xA9, 0xE3, 0x83, 0xB3, 0x49, 0xE3, + 0x82, 0xAA, 0xE3, 0x83, 0xB3, 0xE3, 0x82, 0xB9, + 0x49, 0xE3, 0x82, 0xAA, 0xE3, 0x83, 0xBC, 0xE3, + 0x83, 0xA0, 0x49, 0xE3, 0x82, 0xAB, 0xE3, 0x82, + 0xA4, 0xE3, 0x83, 0xAA, 0x49, 0xE3, 0x82, 0xB1, + 0xE3, 0x83, 0xBC, 0xE3, 0x82, 0xB9, 0x49, 0xE3, + 0x82, 0xB3, 0xE3, 0x83, 0xAB, 0xE3, 0x83, 0x8A, + 0x49, 0xE3, 0x82, 0xBB, 0xE3, 0x83, 0xB3, 0xE3, + // Bytes 2a80 - 2abf + 0x83, 0x81, 0x49, 0xE3, 0x82, 0xBB, 0xE3, 0x83, + 0xB3, 0xE3, 0x83, 0x88, 0x49, 0xE3, 0x83, 0x86, + 0xE3, 0x82, 0x99, 0xE3, 0x82, 0xB7, 0x49, 0xE3, + 0x83, 0x88, 0xE3, 0x82, 0x99, 0xE3, 0x83, 0xAB, + 0x49, 0xE3, 0x83, 0x8E, 0xE3, 0x83, 0x83, 0xE3, + 0x83, 0x88, 0x49, 0xE3, 0x83, 0x8F, 0xE3, 0x82, + 0xA4, 0xE3, 0x83, 0x84, 0x49, 0xE3, 0x83, 0x92, + 0xE3, 0x82, 0x99, 0xE3, 0x83, 0xAB, 0x49, 0xE3, + // Bytes 2ac0 - 2aff + 0x83, 0x92, 0xE3, 0x82, 0x9A, 0xE3, 0x82, 0xB3, + 0x49, 0xE3, 0x83, 0x95, 0xE3, 0x83, 0xA9, 0xE3, + 0x83, 0xB3, 0x49, 0xE3, 0x83, 0x98, 0xE3, 0x82, + 0x9A, 0xE3, 0x82, 0xBD, 0x49, 0xE3, 0x83, 0x98, + 0xE3, 0x83, 0xAB, 0xE3, 0x83, 0x84, 0x49, 0xE3, + 0x83, 0x9B, 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0xAB, + 0x49, 0xE3, 0x83, 0x9B, 0xE3, 0x83, 0xBC, 0xE3, + 0x83, 0xB3, 0x49, 0xE3, 0x83, 0x9E, 0xE3, 0x82, + // Bytes 2b00 - 2b3f + 0xA4, 0xE3, 0x83, 0xAB, 0x49, 0xE3, 0x83, 0x9E, + 0xE3, 0x83, 0x83, 0xE3, 0x83, 0x8F, 0x49, 0xE3, + 0x83, 0x9E, 0xE3, 0x83, 0xAB, 0xE3, 0x82, 0xAF, + 0x49, 0xE3, 0x83, 0xA4, 0xE3, 0x83, 0xBC, 0xE3, + 0x83, 0xAB, 0x49, 0xE3, 0x83, 0xA6, 0xE3, 0x82, + 0xA2, 0xE3, 0x83, 0xB3, 0x49, 0xE3, 0x83, 0xAF, + 0xE3, 0x83, 0x83, 0xE3, 0x83, 0x88, 0x4C, 0xE1, + 0x84, 0x8C, 0xE1, 0x85, 0xAE, 0xE1, 0x84, 0x8B, + // Bytes 2b40 - 2b7f + 0xE1, 0x85, 0xB4, 0x4C, 0xE2, 0x80, 0xB2, 0xE2, + 0x80, 0xB2, 0xE2, 0x80, 0xB2, 0xE2, 0x80, 0xB2, + 0x4C, 0xE2, 0x88, 0xAB, 0xE2, 0x88, 0xAB, 0xE2, + 0x88, 0xAB, 0xE2, 0x88, 0xAB, 0x4C, 0xE3, 0x82, + 0xA2, 0xE3, 0x83, 0xAB, 0xE3, 0x83, 0x95, 0xE3, + 0x82, 0xA1, 0x4C, 0xE3, 0x82, 0xA8, 0xE3, 0x83, + 0xBC, 0xE3, 0x82, 0xAB, 0xE3, 0x83, 0xBC, 0x4C, + 0xE3, 0x82, 0xAB, 0xE3, 0x82, 0x99, 0xE3, 0x83, + // Bytes 2b80 - 2bbf + 0xAD, 0xE3, 0x83, 0xB3, 0x4C, 0xE3, 0x82, 0xAB, + 0xE3, 0x82, 0x99, 0xE3, 0x83, 0xB3, 0xE3, 0x83, + 0x9E, 0x4C, 0xE3, 0x82, 0xAB, 0xE3, 0x83, 0xA9, + 0xE3, 0x83, 0x83, 0xE3, 0x83, 0x88, 0x4C, 0xE3, + 0x82, 0xAB, 0xE3, 0x83, 0xAD, 0xE3, 0x83, 0xAA, + 0xE3, 0x83, 0xBC, 0x4C, 0xE3, 0x82, 0xAD, 0xE3, + 0x82, 0x99, 0xE3, 0x83, 0x8B, 0xE3, 0x83, 0xBC, + 0x4C, 0xE3, 0x82, 0xAD, 0xE3, 0x83, 0xA5, 0xE3, + // Bytes 2bc0 - 2bff + 0x83, 0xAA, 0xE3, 0x83, 0xBC, 0x4C, 0xE3, 0x82, + 0xAF, 0xE3, 0x82, 0x99, 0xE3, 0x83, 0xA9, 0xE3, + 0x83, 0xA0, 0x4C, 0xE3, 0x82, 0xAF, 0xE3, 0x83, + 0xAD, 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0x8D, 0x4C, + 0xE3, 0x82, 0xB5, 0xE3, 0x82, 0xA4, 0xE3, 0x82, + 0xAF, 0xE3, 0x83, 0xAB, 0x4C, 0xE3, 0x82, 0xBF, + 0xE3, 0x82, 0x99, 0xE3, 0x83, 0xBC, 0xE3, 0x82, + 0xB9, 0x4C, 0xE3, 0x83, 0x8F, 0xE3, 0x82, 0x9A, + // Bytes 2c00 - 2c3f + 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0x84, 0x4C, 0xE3, + 0x83, 0x92, 0xE3, 0x82, 0x9A, 0xE3, 0x82, 0xAF, + 0xE3, 0x83, 0xAB, 0x4C, 0xE3, 0x83, 0x95, 0xE3, + 0x82, 0xA3, 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0x88, + 0x4C, 0xE3, 0x83, 0x98, 0xE3, 0x82, 0x99, 0xE3, + 0x83, 0xBC, 0xE3, 0x82, 0xBF, 0x4C, 0xE3, 0x83, + 0x98, 0xE3, 0x82, 0x9A, 0xE3, 0x83, 0x8B, 0xE3, + 0x83, 0x92, 0x4C, 0xE3, 0x83, 0x98, 0xE3, 0x82, + // Bytes 2c40 - 2c7f + 0x9A, 0xE3, 0x83, 0xB3, 0xE3, 0x82, 0xB9, 0x4C, + 0xE3, 0x83, 0x9B, 0xE3, 0x82, 0x99, 0xE3, 0x83, + 0xAB, 0xE3, 0x83, 0x88, 0x4C, 0xE3, 0x83, 0x9E, + 0xE3, 0x82, 0xA4, 0xE3, 0x82, 0xAF, 0xE3, 0x83, + 0xAD, 0x4C, 0xE3, 0x83, 0x9F, 0xE3, 0x82, 0xAF, + 0xE3, 0x83, 0xAD, 0xE3, 0x83, 0xB3, 0x4C, 0xE3, + 0x83, 0xA1, 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0x88, + 0xE3, 0x83, 0xAB, 0x4C, 0xE3, 0x83, 0xAA, 0xE3, + // Bytes 2c80 - 2cbf + 0x83, 0x83, 0xE3, 0x83, 0x88, 0xE3, 0x83, 0xAB, + 0x4C, 0xE3, 0x83, 0xAB, 0xE3, 0x83, 0x92, 0xE3, + 0x82, 0x9A, 0xE3, 0x83, 0xBC, 0x4C, 0xE6, 0xA0, + 0xAA, 0xE5, 0xBC, 0x8F, 0xE4, 0xBC, 0x9A, 0xE7, + 0xA4, 0xBE, 0x4E, 0x28, 0xE1, 0x84, 0x8B, 0xE1, + 0x85, 0xA9, 0xE1, 0x84, 0x92, 0xE1, 0x85, 0xAE, + 0x29, 0x4F, 0xD8, 0xAC, 0xD9, 0x84, 0x20, 0xD8, + 0xAC, 0xD9, 0x84, 0xD8, 0xA7, 0xD9, 0x84, 0xD9, + // Bytes 2cc0 - 2cff + 0x87, 0x4F, 0xE1, 0x84, 0x8E, 0xE1, 0x85, 0xA1, + 0xE1, 0x86, 0xB7, 0xE1, 0x84, 0x80, 0xE1, 0x85, + 0xA9, 0x4F, 0xE3, 0x82, 0xA2, 0xE3, 0x83, 0x8F, + 0xE3, 0x82, 0x9A, 0xE3, 0x83, 0xBC, 0xE3, 0x83, + 0x88, 0x4F, 0xE3, 0x82, 0xA2, 0xE3, 0x83, 0xB3, + 0xE3, 0x83, 0x98, 0xE3, 0x82, 0x9A, 0xE3, 0x82, + 0xA2, 0x4F, 0xE3, 0x82, 0xAD, 0xE3, 0x83, 0xAD, + 0xE3, 0x83, 0xAF, 0xE3, 0x83, 0x83, 0xE3, 0x83, + // Bytes 2d00 - 2d3f + 0x88, 0x4F, 0xE3, 0x82, 0xB5, 0xE3, 0x83, 0xB3, + 0xE3, 0x83, 0x81, 0xE3, 0x83, 0xBC, 0xE3, 0x83, + 0xA0, 0x4F, 0xE3, 0x83, 0x8F, 0xE3, 0x82, 0x99, + 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0xAC, 0xE3, 0x83, + 0xAB, 0x4F, 0xE3, 0x83, 0x98, 0xE3, 0x82, 0xAF, + 0xE3, 0x82, 0xBF, 0xE3, 0x83, 0xBC, 0xE3, 0x83, + 0xAB, 0x4F, 0xE3, 0x83, 0x9B, 0xE3, 0x82, 0x9A, + 0xE3, 0x82, 0xA4, 0xE3, 0x83, 0xB3, 0xE3, 0x83, + // Bytes 2d40 - 2d7f + 0x88, 0x4F, 0xE3, 0x83, 0x9E, 0xE3, 0x83, 0xB3, + 0xE3, 0x82, 0xB7, 0xE3, 0x83, 0xA7, 0xE3, 0x83, + 0xB3, 0x4F, 0xE3, 0x83, 0xA1, 0xE3, 0x82, 0xAB, + 0xE3, 0x82, 0x99, 0xE3, 0x83, 0x88, 0xE3, 0x83, + 0xB3, 0x4F, 0xE3, 0x83, 0xAB, 0xE3, 0x83, 0xBC, + 0xE3, 0x83, 0x95, 0xE3, 0x82, 0x99, 0xE3, 0x83, + 0xAB, 0x51, 0x28, 0xE1, 0x84, 0x8B, 0xE1, 0x85, + 0xA9, 0xE1, 0x84, 0x8C, 0xE1, 0x85, 0xA5, 0xE1, + // Bytes 2d80 - 2dbf + 0x86, 0xAB, 0x29, 0x52, 0xE3, 0x82, 0xAD, 0xE3, + 0x82, 0x99, 0xE3, 0x83, 0xAB, 0xE3, 0x82, 0xBF, + 0xE3, 0x82, 0x99, 0xE3, 0x83, 0xBC, 0x52, 0xE3, + 0x82, 0xAD, 0xE3, 0x83, 0xAD, 0xE3, 0x82, 0xAF, + 0xE3, 0x82, 0x99, 0xE3, 0x83, 0xA9, 0xE3, 0x83, + 0xA0, 0x52, 0xE3, 0x82, 0xAD, 0xE3, 0x83, 0xAD, + 0xE3, 0x83, 0xA1, 0xE3, 0x83, 0xBC, 0xE3, 0x83, + 0x88, 0xE3, 0x83, 0xAB, 0x52, 0xE3, 0x82, 0xAF, + // Bytes 2dc0 - 2dff + 0xE3, 0x82, 0x99, 0xE3, 0x83, 0xA9, 0xE3, 0x83, + 0xA0, 0xE3, 0x83, 0x88, 0xE3, 0x83, 0xB3, 0x52, + 0xE3, 0x82, 0xAF, 0xE3, 0x83, 0xAB, 0xE3, 0x82, + 0xBB, 0xE3, 0x82, 0x99, 0xE3, 0x82, 0xA4, 0xE3, + 0x83, 0xAD, 0x52, 0xE3, 0x83, 0x8F, 0xE3, 0x82, + 0x9A, 0xE3, 0x83, 0xBC, 0xE3, 0x82, 0xBB, 0xE3, + 0x83, 0xB3, 0xE3, 0x83, 0x88, 0x52, 0xE3, 0x83, + 0x92, 0xE3, 0x82, 0x9A, 0xE3, 0x82, 0xA2, 0xE3, + // Bytes 2e00 - 2e3f + 0x82, 0xB9, 0xE3, 0x83, 0x88, 0xE3, 0x83, 0xAB, + 0x52, 0xE3, 0x83, 0x95, 0xE3, 0x82, 0x99, 0xE3, + 0x83, 0x83, 0xE3, 0x82, 0xB7, 0xE3, 0x82, 0xA7, + 0xE3, 0x83, 0xAB, 0x52, 0xE3, 0x83, 0x9F, 0xE3, + 0x83, 0xAA, 0xE3, 0x83, 0x8F, 0xE3, 0x82, 0x99, + 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0xAB, 0x52, 0xE3, + 0x83, 0xAC, 0xE3, 0x83, 0xB3, 0xE3, 0x83, 0x88, + 0xE3, 0x82, 0xB1, 0xE3, 0x82, 0x99, 0xE3, 0x83, + // Bytes 2e40 - 2e7f + 0xB3, 0x61, 0xD8, 0xB5, 0xD9, 0x84, 0xD9, 0x89, + 0x20, 0xD8, 0xA7, 0xD9, 0x84, 0xD9, 0x84, 0xD9, + 0x87, 0x20, 0xD8, 0xB9, 0xD9, 0x84, 0xD9, 0x8A, + 0xD9, 0x87, 0x20, 0xD9, 0x88, 0xD8, 0xB3, 0xD9, + 0x84, 0xD9, 0x85, 0x86, 0xE0, 0xB3, 0x86, 0xE0, + 0xB3, 0x82, 0x86, 0xE0, 0xB7, 0x99, 0xE0, 0xB7, + 0x8F, 0x09, 0xE0, 0xB7, 0x99, 0xE0, 0xB7, 0x8F, + 0xE0, 0xB7, 0x8A, 0x11, 0x44, 0x44, 0x5A, 0xCC, + // Bytes 2e80 - 2ebf + 0x8C, 0xC9, 0x44, 0x44, 0x7A, 0xCC, 0x8C, 0xC9, + 0x44, 0x64, 0x7A, 0xCC, 0x8C, 0xC9, 0x46, 0xD9, + 0x84, 0xD8, 0xA7, 0xD9, 0x93, 0xC9, 0x46, 0xD9, + 0x84, 0xD8, 0xA7, 0xD9, 0x94, 0xC9, 0x46, 0xD9, + 0x84, 0xD8, 0xA7, 0xD9, 0x95, 0xB5, 0x49, 0xE3, + 0x83, 0xA1, 0xE3, 0x82, 0xAB, 0xE3, 0x82, 0x99, + 0x0D, 0x4C, 0xE3, 0x82, 0xAD, 0xE3, 0x82, 0x99, + 0xE3, 0x82, 0xAB, 0xE3, 0x82, 0x99, 0x0D, 0x4C, + // Bytes 2ec0 - 2eff + 0xE3, 0x82, 0xB3, 0xE3, 0x83, 0xBC, 0xE3, 0x83, + 0x9B, 0xE3, 0x82, 0x9A, 0x0D, 0x4C, 0xE3, 0x83, + 0xA4, 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0x88, 0xE3, + 0x82, 0x99, 0x0D, 0x4F, 0xE3, 0x82, 0xA4, 0xE3, + 0x83, 0x8B, 0xE3, 0x83, 0xB3, 0xE3, 0x82, 0xAF, + 0xE3, 0x82, 0x99, 0x0D, 0x4F, 0xE3, 0x82, 0xB7, + 0xE3, 0x83, 0xAA, 0xE3, 0x83, 0xB3, 0xE3, 0x82, + 0xAF, 0xE3, 0x82, 0x99, 0x0D, 0x4F, 0xE3, 0x83, + // Bytes 2f00 - 2f3f + 0x98, 0xE3, 0x82, 0x9A, 0xE3, 0x83, 0xBC, 0xE3, + 0x82, 0xB7, 0xE3, 0x82, 0x99, 0x0D, 0x4F, 0xE3, + 0x83, 0x9B, 0xE3, 0x82, 0x9A, 0xE3, 0x83, 0xB3, + 0xE3, 0x83, 0x88, 0xE3, 0x82, 0x99, 0x0D, 0x52, + 0xE3, 0x82, 0xA8, 0xE3, 0x82, 0xB9, 0xE3, 0x82, + 0xAF, 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0x88, 0xE3, + 0x82, 0x99, 0x0D, 0x52, 0xE3, 0x83, 0x95, 0xE3, + 0x82, 0xA1, 0xE3, 0x83, 0xA9, 0xE3, 0x83, 0x83, + // Bytes 2f40 - 2f7f + 0xE3, 0x83, 0x88, 0xE3, 0x82, 0x99, 0x0D, 0x03, + 0x3C, 0xCC, 0xB8, 0x05, 0x03, 0x3D, 0xCC, 0xB8, + 0x05, 0x03, 0x3E, 0xCC, 0xB8, 0x05, 0x03, 0x41, + 0xCC, 0x80, 0xC9, 0x03, 0x41, 0xCC, 0x81, 0xC9, + 0x03, 0x41, 0xCC, 0x83, 0xC9, 0x03, 0x41, 0xCC, + 0x84, 0xC9, 0x03, 0x41, 0xCC, 0x89, 0xC9, 0x03, + 0x41, 0xCC, 0x8C, 0xC9, 0x03, 0x41, 0xCC, 0x8F, + 0xC9, 0x03, 0x41, 0xCC, 0x91, 0xC9, 0x03, 0x41, + // Bytes 2f80 - 2fbf + 0xCC, 0xA5, 0xB5, 0x03, 0x41, 0xCC, 0xA8, 0xA5, + 0x03, 0x42, 0xCC, 0x87, 0xC9, 0x03, 0x42, 0xCC, + 0xA3, 0xB5, 0x03, 0x42, 0xCC, 0xB1, 0xB5, 0x03, + 0x43, 0xCC, 0x81, 0xC9, 0x03, 0x43, 0xCC, 0x82, + 0xC9, 0x03, 0x43, 0xCC, 0x87, 0xC9, 0x03, 0x43, + 0xCC, 0x8C, 0xC9, 0x03, 0x44, 0xCC, 0x87, 0xC9, + 0x03, 0x44, 0xCC, 0x8C, 0xC9, 0x03, 0x44, 0xCC, + 0xA3, 0xB5, 0x03, 0x44, 0xCC, 0xA7, 0xA5, 0x03, + // Bytes 2fc0 - 2fff + 0x44, 0xCC, 0xAD, 0xB5, 0x03, 0x44, 0xCC, 0xB1, + 0xB5, 0x03, 0x45, 0xCC, 0x80, 0xC9, 0x03, 0x45, + 0xCC, 0x81, 0xC9, 0x03, 0x45, 0xCC, 0x83, 0xC9, + 0x03, 0x45, 0xCC, 0x86, 0xC9, 0x03, 0x45, 0xCC, + 0x87, 0xC9, 0x03, 0x45, 0xCC, 0x88, 0xC9, 0x03, + 0x45, 0xCC, 0x89, 0xC9, 0x03, 0x45, 0xCC, 0x8C, + 0xC9, 0x03, 0x45, 0xCC, 0x8F, 0xC9, 0x03, 0x45, + 0xCC, 0x91, 0xC9, 0x03, 0x45, 0xCC, 0xA8, 0xA5, + // Bytes 3000 - 303f + 0x03, 0x45, 0xCC, 0xAD, 0xB5, 0x03, 0x45, 0xCC, + 0xB0, 0xB5, 0x03, 0x46, 0xCC, 0x87, 0xC9, 0x03, + 0x47, 0xCC, 0x81, 0xC9, 0x03, 0x47, 0xCC, 0x82, + 0xC9, 0x03, 0x47, 0xCC, 0x84, 0xC9, 0x03, 0x47, + 0xCC, 0x86, 0xC9, 0x03, 0x47, 0xCC, 0x87, 0xC9, + 0x03, 0x47, 0xCC, 0x8C, 0xC9, 0x03, 0x47, 0xCC, + 0xA7, 0xA5, 0x03, 0x48, 0xCC, 0x82, 0xC9, 0x03, + 0x48, 0xCC, 0x87, 0xC9, 0x03, 0x48, 0xCC, 0x88, + // Bytes 3040 - 307f + 0xC9, 0x03, 0x48, 0xCC, 0x8C, 0xC9, 0x03, 0x48, + 0xCC, 0xA3, 0xB5, 0x03, 0x48, 0xCC, 0xA7, 0xA5, + 0x03, 0x48, 0xCC, 0xAE, 0xB5, 0x03, 0x49, 0xCC, + 0x80, 0xC9, 0x03, 0x49, 0xCC, 0x81, 0xC9, 0x03, + 0x49, 0xCC, 0x82, 0xC9, 0x03, 0x49, 0xCC, 0x83, + 0xC9, 0x03, 0x49, 0xCC, 0x84, 0xC9, 0x03, 0x49, + 0xCC, 0x86, 0xC9, 0x03, 0x49, 0xCC, 0x87, 0xC9, + 0x03, 0x49, 0xCC, 0x89, 0xC9, 0x03, 0x49, 0xCC, + // Bytes 3080 - 30bf + 0x8C, 0xC9, 0x03, 0x49, 0xCC, 0x8F, 0xC9, 0x03, + 0x49, 0xCC, 0x91, 0xC9, 0x03, 0x49, 0xCC, 0xA3, + 0xB5, 0x03, 0x49, 0xCC, 0xA8, 0xA5, 0x03, 0x49, + 0xCC, 0xB0, 0xB5, 0x03, 0x4A, 0xCC, 0x82, 0xC9, + 0x03, 0x4B, 0xCC, 0x81, 0xC9, 0x03, 0x4B, 0xCC, + 0x8C, 0xC9, 0x03, 0x4B, 0xCC, 0xA3, 0xB5, 0x03, + 0x4B, 0xCC, 0xA7, 0xA5, 0x03, 0x4B, 0xCC, 0xB1, + 0xB5, 0x03, 0x4C, 0xCC, 0x81, 0xC9, 0x03, 0x4C, + // Bytes 30c0 - 30ff + 0xCC, 0x8C, 0xC9, 0x03, 0x4C, 0xCC, 0xA7, 0xA5, + 0x03, 0x4C, 0xCC, 0xAD, 0xB5, 0x03, 0x4C, 0xCC, + 0xB1, 0xB5, 0x03, 0x4D, 0xCC, 0x81, 0xC9, 0x03, + 0x4D, 0xCC, 0x87, 0xC9, 0x03, 0x4D, 0xCC, 0xA3, + 0xB5, 0x03, 0x4E, 0xCC, 0x80, 0xC9, 0x03, 0x4E, + 0xCC, 0x81, 0xC9, 0x03, 0x4E, 0xCC, 0x83, 0xC9, + 0x03, 0x4E, 0xCC, 0x87, 0xC9, 0x03, 0x4E, 0xCC, + 0x8C, 0xC9, 0x03, 0x4E, 0xCC, 0xA3, 0xB5, 0x03, + // Bytes 3100 - 313f + 0x4E, 0xCC, 0xA7, 0xA5, 0x03, 0x4E, 0xCC, 0xAD, + 0xB5, 0x03, 0x4E, 0xCC, 0xB1, 0xB5, 0x03, 0x4F, + 0xCC, 0x80, 0xC9, 0x03, 0x4F, 0xCC, 0x81, 0xC9, + 0x03, 0x4F, 0xCC, 0x86, 0xC9, 0x03, 0x4F, 0xCC, + 0x89, 0xC9, 0x03, 0x4F, 0xCC, 0x8B, 0xC9, 0x03, + 0x4F, 0xCC, 0x8C, 0xC9, 0x03, 0x4F, 0xCC, 0x8F, + 0xC9, 0x03, 0x4F, 0xCC, 0x91, 0xC9, 0x03, 0x50, + 0xCC, 0x81, 0xC9, 0x03, 0x50, 0xCC, 0x87, 0xC9, + // Bytes 3140 - 317f + 0x03, 0x52, 0xCC, 0x81, 0xC9, 0x03, 0x52, 0xCC, + 0x87, 0xC9, 0x03, 0x52, 0xCC, 0x8C, 0xC9, 0x03, + 0x52, 0xCC, 0x8F, 0xC9, 0x03, 0x52, 0xCC, 0x91, + 0xC9, 0x03, 0x52, 0xCC, 0xA7, 0xA5, 0x03, 0x52, + 0xCC, 0xB1, 0xB5, 0x03, 0x53, 0xCC, 0x82, 0xC9, + 0x03, 0x53, 0xCC, 0x87, 0xC9, 0x03, 0x53, 0xCC, + 0xA6, 0xB5, 0x03, 0x53, 0xCC, 0xA7, 0xA5, 0x03, + 0x54, 0xCC, 0x87, 0xC9, 0x03, 0x54, 0xCC, 0x8C, + // Bytes 3180 - 31bf + 0xC9, 0x03, 0x54, 0xCC, 0xA3, 0xB5, 0x03, 0x54, + 0xCC, 0xA6, 0xB5, 0x03, 0x54, 0xCC, 0xA7, 0xA5, + 0x03, 0x54, 0xCC, 0xAD, 0xB5, 0x03, 0x54, 0xCC, + 0xB1, 0xB5, 0x03, 0x55, 0xCC, 0x80, 0xC9, 0x03, + 0x55, 0xCC, 0x81, 0xC9, 0x03, 0x55, 0xCC, 0x82, + 0xC9, 0x03, 0x55, 0xCC, 0x86, 0xC9, 0x03, 0x55, + 0xCC, 0x89, 0xC9, 0x03, 0x55, 0xCC, 0x8A, 0xC9, + 0x03, 0x55, 0xCC, 0x8B, 0xC9, 0x03, 0x55, 0xCC, + // Bytes 31c0 - 31ff + 0x8C, 0xC9, 0x03, 0x55, 0xCC, 0x8F, 0xC9, 0x03, + 0x55, 0xCC, 0x91, 0xC9, 0x03, 0x55, 0xCC, 0xA3, + 0xB5, 0x03, 0x55, 0xCC, 0xA4, 0xB5, 0x03, 0x55, + 0xCC, 0xA8, 0xA5, 0x03, 0x55, 0xCC, 0xAD, 0xB5, + 0x03, 0x55, 0xCC, 0xB0, 0xB5, 0x03, 0x56, 0xCC, + 0x83, 0xC9, 0x03, 0x56, 0xCC, 0xA3, 0xB5, 0x03, + 0x57, 0xCC, 0x80, 0xC9, 0x03, 0x57, 0xCC, 0x81, + 0xC9, 0x03, 0x57, 0xCC, 0x82, 0xC9, 0x03, 0x57, + // Bytes 3200 - 323f + 0xCC, 0x87, 0xC9, 0x03, 0x57, 0xCC, 0x88, 0xC9, + 0x03, 0x57, 0xCC, 0xA3, 0xB5, 0x03, 0x58, 0xCC, + 0x87, 0xC9, 0x03, 0x58, 0xCC, 0x88, 0xC9, 0x03, + 0x59, 0xCC, 0x80, 0xC9, 0x03, 0x59, 0xCC, 0x81, + 0xC9, 0x03, 0x59, 0xCC, 0x82, 0xC9, 0x03, 0x59, + 0xCC, 0x83, 0xC9, 0x03, 0x59, 0xCC, 0x84, 0xC9, + 0x03, 0x59, 0xCC, 0x87, 0xC9, 0x03, 0x59, 0xCC, + 0x88, 0xC9, 0x03, 0x59, 0xCC, 0x89, 0xC9, 0x03, + // Bytes 3240 - 327f + 0x59, 0xCC, 0xA3, 0xB5, 0x03, 0x5A, 0xCC, 0x81, + 0xC9, 0x03, 0x5A, 0xCC, 0x82, 0xC9, 0x03, 0x5A, + 0xCC, 0x87, 0xC9, 0x03, 0x5A, 0xCC, 0x8C, 0xC9, + 0x03, 0x5A, 0xCC, 0xA3, 0xB5, 0x03, 0x5A, 0xCC, + 0xB1, 0xB5, 0x03, 0x61, 0xCC, 0x80, 0xC9, 0x03, + 0x61, 0xCC, 0x81, 0xC9, 0x03, 0x61, 0xCC, 0x83, + 0xC9, 0x03, 0x61, 0xCC, 0x84, 0xC9, 0x03, 0x61, + 0xCC, 0x89, 0xC9, 0x03, 0x61, 0xCC, 0x8C, 0xC9, + // Bytes 3280 - 32bf + 0x03, 0x61, 0xCC, 0x8F, 0xC9, 0x03, 0x61, 0xCC, + 0x91, 0xC9, 0x03, 0x61, 0xCC, 0xA5, 0xB5, 0x03, + 0x61, 0xCC, 0xA8, 0xA5, 0x03, 0x62, 0xCC, 0x87, + 0xC9, 0x03, 0x62, 0xCC, 0xA3, 0xB5, 0x03, 0x62, + 0xCC, 0xB1, 0xB5, 0x03, 0x63, 0xCC, 0x81, 0xC9, + 0x03, 0x63, 0xCC, 0x82, 0xC9, 0x03, 0x63, 0xCC, + 0x87, 0xC9, 0x03, 0x63, 0xCC, 0x8C, 0xC9, 0x03, + 0x64, 0xCC, 0x87, 0xC9, 0x03, 0x64, 0xCC, 0x8C, + // Bytes 32c0 - 32ff + 0xC9, 0x03, 0x64, 0xCC, 0xA3, 0xB5, 0x03, 0x64, + 0xCC, 0xA7, 0xA5, 0x03, 0x64, 0xCC, 0xAD, 0xB5, + 0x03, 0x64, 0xCC, 0xB1, 0xB5, 0x03, 0x65, 0xCC, + 0x80, 0xC9, 0x03, 0x65, 0xCC, 0x81, 0xC9, 0x03, + 0x65, 0xCC, 0x83, 0xC9, 0x03, 0x65, 0xCC, 0x86, + 0xC9, 0x03, 0x65, 0xCC, 0x87, 0xC9, 0x03, 0x65, + 0xCC, 0x88, 0xC9, 0x03, 0x65, 0xCC, 0x89, 0xC9, + 0x03, 0x65, 0xCC, 0x8C, 0xC9, 0x03, 0x65, 0xCC, + // Bytes 3300 - 333f + 0x8F, 0xC9, 0x03, 0x65, 0xCC, 0x91, 0xC9, 0x03, + 0x65, 0xCC, 0xA8, 0xA5, 0x03, 0x65, 0xCC, 0xAD, + 0xB5, 0x03, 0x65, 0xCC, 0xB0, 0xB5, 0x03, 0x66, + 0xCC, 0x87, 0xC9, 0x03, 0x67, 0xCC, 0x81, 0xC9, + 0x03, 0x67, 0xCC, 0x82, 0xC9, 0x03, 0x67, 0xCC, + 0x84, 0xC9, 0x03, 0x67, 0xCC, 0x86, 0xC9, 0x03, + 0x67, 0xCC, 0x87, 0xC9, 0x03, 0x67, 0xCC, 0x8C, + 0xC9, 0x03, 0x67, 0xCC, 0xA7, 0xA5, 0x03, 0x68, + // Bytes 3340 - 337f + 0xCC, 0x82, 0xC9, 0x03, 0x68, 0xCC, 0x87, 0xC9, + 0x03, 0x68, 0xCC, 0x88, 0xC9, 0x03, 0x68, 0xCC, + 0x8C, 0xC9, 0x03, 0x68, 0xCC, 0xA3, 0xB5, 0x03, + 0x68, 0xCC, 0xA7, 0xA5, 0x03, 0x68, 0xCC, 0xAE, + 0xB5, 0x03, 0x68, 0xCC, 0xB1, 0xB5, 0x03, 0x69, + 0xCC, 0x80, 0xC9, 0x03, 0x69, 0xCC, 0x81, 0xC9, + 0x03, 0x69, 0xCC, 0x82, 0xC9, 0x03, 0x69, 0xCC, + 0x83, 0xC9, 0x03, 0x69, 0xCC, 0x84, 0xC9, 0x03, + // Bytes 3380 - 33bf + 0x69, 0xCC, 0x86, 0xC9, 0x03, 0x69, 0xCC, 0x89, + 0xC9, 0x03, 0x69, 0xCC, 0x8C, 0xC9, 0x03, 0x69, + 0xCC, 0x8F, 0xC9, 0x03, 0x69, 0xCC, 0x91, 0xC9, + 0x03, 0x69, 0xCC, 0xA3, 0xB5, 0x03, 0x69, 0xCC, + 0xA8, 0xA5, 0x03, 0x69, 0xCC, 0xB0, 0xB5, 0x03, + 0x6A, 0xCC, 0x82, 0xC9, 0x03, 0x6A, 0xCC, 0x8C, + 0xC9, 0x03, 0x6B, 0xCC, 0x81, 0xC9, 0x03, 0x6B, + 0xCC, 0x8C, 0xC9, 0x03, 0x6B, 0xCC, 0xA3, 0xB5, + // Bytes 33c0 - 33ff + 0x03, 0x6B, 0xCC, 0xA7, 0xA5, 0x03, 0x6B, 0xCC, + 0xB1, 0xB5, 0x03, 0x6C, 0xCC, 0x81, 0xC9, 0x03, + 0x6C, 0xCC, 0x8C, 0xC9, 0x03, 0x6C, 0xCC, 0xA7, + 0xA5, 0x03, 0x6C, 0xCC, 0xAD, 0xB5, 0x03, 0x6C, + 0xCC, 0xB1, 0xB5, 0x03, 0x6D, 0xCC, 0x81, 0xC9, + 0x03, 0x6D, 0xCC, 0x87, 0xC9, 0x03, 0x6D, 0xCC, + 0xA3, 0xB5, 0x03, 0x6E, 0xCC, 0x80, 0xC9, 0x03, + 0x6E, 0xCC, 0x81, 0xC9, 0x03, 0x6E, 0xCC, 0x83, + // Bytes 3400 - 343f + 0xC9, 0x03, 0x6E, 0xCC, 0x87, 0xC9, 0x03, 0x6E, + 0xCC, 0x8C, 0xC9, 0x03, 0x6E, 0xCC, 0xA3, 0xB5, + 0x03, 0x6E, 0xCC, 0xA7, 0xA5, 0x03, 0x6E, 0xCC, + 0xAD, 0xB5, 0x03, 0x6E, 0xCC, 0xB1, 0xB5, 0x03, + 0x6F, 0xCC, 0x80, 0xC9, 0x03, 0x6F, 0xCC, 0x81, + 0xC9, 0x03, 0x6F, 0xCC, 0x86, 0xC9, 0x03, 0x6F, + 0xCC, 0x89, 0xC9, 0x03, 0x6F, 0xCC, 0x8B, 0xC9, + 0x03, 0x6F, 0xCC, 0x8C, 0xC9, 0x03, 0x6F, 0xCC, + // Bytes 3440 - 347f + 0x8F, 0xC9, 0x03, 0x6F, 0xCC, 0x91, 0xC9, 0x03, + 0x70, 0xCC, 0x81, 0xC9, 0x03, 0x70, 0xCC, 0x87, + 0xC9, 0x03, 0x72, 0xCC, 0x81, 0xC9, 0x03, 0x72, + 0xCC, 0x87, 0xC9, 0x03, 0x72, 0xCC, 0x8C, 0xC9, + 0x03, 0x72, 0xCC, 0x8F, 0xC9, 0x03, 0x72, 0xCC, + 0x91, 0xC9, 0x03, 0x72, 0xCC, 0xA7, 0xA5, 0x03, + 0x72, 0xCC, 0xB1, 0xB5, 0x03, 0x73, 0xCC, 0x82, + 0xC9, 0x03, 0x73, 0xCC, 0x87, 0xC9, 0x03, 0x73, + // Bytes 3480 - 34bf + 0xCC, 0xA6, 0xB5, 0x03, 0x73, 0xCC, 0xA7, 0xA5, + 0x03, 0x74, 0xCC, 0x87, 0xC9, 0x03, 0x74, 0xCC, + 0x88, 0xC9, 0x03, 0x74, 0xCC, 0x8C, 0xC9, 0x03, + 0x74, 0xCC, 0xA3, 0xB5, 0x03, 0x74, 0xCC, 0xA6, + 0xB5, 0x03, 0x74, 0xCC, 0xA7, 0xA5, 0x03, 0x74, + 0xCC, 0xAD, 0xB5, 0x03, 0x74, 0xCC, 0xB1, 0xB5, + 0x03, 0x75, 0xCC, 0x80, 0xC9, 0x03, 0x75, 0xCC, + 0x81, 0xC9, 0x03, 0x75, 0xCC, 0x82, 0xC9, 0x03, + // Bytes 34c0 - 34ff + 0x75, 0xCC, 0x86, 0xC9, 0x03, 0x75, 0xCC, 0x89, + 0xC9, 0x03, 0x75, 0xCC, 0x8A, 0xC9, 0x03, 0x75, + 0xCC, 0x8B, 0xC9, 0x03, 0x75, 0xCC, 0x8C, 0xC9, + 0x03, 0x75, 0xCC, 0x8F, 0xC9, 0x03, 0x75, 0xCC, + 0x91, 0xC9, 0x03, 0x75, 0xCC, 0xA3, 0xB5, 0x03, + 0x75, 0xCC, 0xA4, 0xB5, 0x03, 0x75, 0xCC, 0xA8, + 0xA5, 0x03, 0x75, 0xCC, 0xAD, 0xB5, 0x03, 0x75, + 0xCC, 0xB0, 0xB5, 0x03, 0x76, 0xCC, 0x83, 0xC9, + // Bytes 3500 - 353f + 0x03, 0x76, 0xCC, 0xA3, 0xB5, 0x03, 0x77, 0xCC, + 0x80, 0xC9, 0x03, 0x77, 0xCC, 0x81, 0xC9, 0x03, + 0x77, 0xCC, 0x82, 0xC9, 0x03, 0x77, 0xCC, 0x87, + 0xC9, 0x03, 0x77, 0xCC, 0x88, 0xC9, 0x03, 0x77, + 0xCC, 0x8A, 0xC9, 0x03, 0x77, 0xCC, 0xA3, 0xB5, + 0x03, 0x78, 0xCC, 0x87, 0xC9, 0x03, 0x78, 0xCC, + 0x88, 0xC9, 0x03, 0x79, 0xCC, 0x80, 0xC9, 0x03, + 0x79, 0xCC, 0x81, 0xC9, 0x03, 0x79, 0xCC, 0x82, + // Bytes 3540 - 357f + 0xC9, 0x03, 0x79, 0xCC, 0x83, 0xC9, 0x03, 0x79, + 0xCC, 0x84, 0xC9, 0x03, 0x79, 0xCC, 0x87, 0xC9, + 0x03, 0x79, 0xCC, 0x88, 0xC9, 0x03, 0x79, 0xCC, + 0x89, 0xC9, 0x03, 0x79, 0xCC, 0x8A, 0xC9, 0x03, + 0x79, 0xCC, 0xA3, 0xB5, 0x03, 0x7A, 0xCC, 0x81, + 0xC9, 0x03, 0x7A, 0xCC, 0x82, 0xC9, 0x03, 0x7A, + 0xCC, 0x87, 0xC9, 0x03, 0x7A, 0xCC, 0x8C, 0xC9, + 0x03, 0x7A, 0xCC, 0xA3, 0xB5, 0x03, 0x7A, 0xCC, + // Bytes 3580 - 35bf + 0xB1, 0xB5, 0x04, 0xC2, 0xA8, 0xCC, 0x80, 0xCA, + 0x04, 0xC2, 0xA8, 0xCC, 0x81, 0xCA, 0x04, 0xC2, + 0xA8, 0xCD, 0x82, 0xCA, 0x04, 0xC3, 0x86, 0xCC, + 0x81, 0xC9, 0x04, 0xC3, 0x86, 0xCC, 0x84, 0xC9, + 0x04, 0xC3, 0x98, 0xCC, 0x81, 0xC9, 0x04, 0xC3, + 0xA6, 0xCC, 0x81, 0xC9, 0x04, 0xC3, 0xA6, 0xCC, + 0x84, 0xC9, 0x04, 0xC3, 0xB8, 0xCC, 0x81, 0xC9, + 0x04, 0xC5, 0xBF, 0xCC, 0x87, 0xC9, 0x04, 0xC6, + // Bytes 35c0 - 35ff + 0xB7, 0xCC, 0x8C, 0xC9, 0x04, 0xCA, 0x92, 0xCC, + 0x8C, 0xC9, 0x04, 0xCE, 0x91, 0xCC, 0x80, 0xC9, + 0x04, 0xCE, 0x91, 0xCC, 0x81, 0xC9, 0x04, 0xCE, + 0x91, 0xCC, 0x84, 0xC9, 0x04, 0xCE, 0x91, 0xCC, + 0x86, 0xC9, 0x04, 0xCE, 0x91, 0xCD, 0x85, 0xD9, + 0x04, 0xCE, 0x95, 0xCC, 0x80, 0xC9, 0x04, 0xCE, + 0x95, 0xCC, 0x81, 0xC9, 0x04, 0xCE, 0x97, 0xCC, + 0x80, 0xC9, 0x04, 0xCE, 0x97, 0xCC, 0x81, 0xC9, + // Bytes 3600 - 363f + 0x04, 0xCE, 0x97, 0xCD, 0x85, 0xD9, 0x04, 0xCE, + 0x99, 0xCC, 0x80, 0xC9, 0x04, 0xCE, 0x99, 0xCC, + 0x81, 0xC9, 0x04, 0xCE, 0x99, 0xCC, 0x84, 0xC9, + 0x04, 0xCE, 0x99, 0xCC, 0x86, 0xC9, 0x04, 0xCE, + 0x99, 0xCC, 0x88, 0xC9, 0x04, 0xCE, 0x9F, 0xCC, + 0x80, 0xC9, 0x04, 0xCE, 0x9F, 0xCC, 0x81, 0xC9, + 0x04, 0xCE, 0xA1, 0xCC, 0x94, 0xC9, 0x04, 0xCE, + 0xA5, 0xCC, 0x80, 0xC9, 0x04, 0xCE, 0xA5, 0xCC, + // Bytes 3640 - 367f + 0x81, 0xC9, 0x04, 0xCE, 0xA5, 0xCC, 0x84, 0xC9, + 0x04, 0xCE, 0xA5, 0xCC, 0x86, 0xC9, 0x04, 0xCE, + 0xA5, 0xCC, 0x88, 0xC9, 0x04, 0xCE, 0xA9, 0xCC, + 0x80, 0xC9, 0x04, 0xCE, 0xA9, 0xCC, 0x81, 0xC9, + 0x04, 0xCE, 0xA9, 0xCD, 0x85, 0xD9, 0x04, 0xCE, + 0xB1, 0xCC, 0x84, 0xC9, 0x04, 0xCE, 0xB1, 0xCC, + 0x86, 0xC9, 0x04, 0xCE, 0xB1, 0xCD, 0x85, 0xD9, + 0x04, 0xCE, 0xB5, 0xCC, 0x80, 0xC9, 0x04, 0xCE, + // Bytes 3680 - 36bf + 0xB5, 0xCC, 0x81, 0xC9, 0x04, 0xCE, 0xB7, 0xCD, + 0x85, 0xD9, 0x04, 0xCE, 0xB9, 0xCC, 0x80, 0xC9, + 0x04, 0xCE, 0xB9, 0xCC, 0x81, 0xC9, 0x04, 0xCE, + 0xB9, 0xCC, 0x84, 0xC9, 0x04, 0xCE, 0xB9, 0xCC, + 0x86, 0xC9, 0x04, 0xCE, 0xB9, 0xCD, 0x82, 0xC9, + 0x04, 0xCE, 0xBF, 0xCC, 0x80, 0xC9, 0x04, 0xCE, + 0xBF, 0xCC, 0x81, 0xC9, 0x04, 0xCF, 0x81, 0xCC, + 0x93, 0xC9, 0x04, 0xCF, 0x81, 0xCC, 0x94, 0xC9, + // Bytes 36c0 - 36ff + 0x04, 0xCF, 0x85, 0xCC, 0x80, 0xC9, 0x04, 0xCF, + 0x85, 0xCC, 0x81, 0xC9, 0x04, 0xCF, 0x85, 0xCC, + 0x84, 0xC9, 0x04, 0xCF, 0x85, 0xCC, 0x86, 0xC9, + 0x04, 0xCF, 0x85, 0xCD, 0x82, 0xC9, 0x04, 0xCF, + 0x89, 0xCD, 0x85, 0xD9, 0x04, 0xCF, 0x92, 0xCC, + 0x81, 0xC9, 0x04, 0xCF, 0x92, 0xCC, 0x88, 0xC9, + 0x04, 0xD0, 0x86, 0xCC, 0x88, 0xC9, 0x04, 0xD0, + 0x90, 0xCC, 0x86, 0xC9, 0x04, 0xD0, 0x90, 0xCC, + // Bytes 3700 - 373f + 0x88, 0xC9, 0x04, 0xD0, 0x93, 0xCC, 0x81, 0xC9, + 0x04, 0xD0, 0x95, 0xCC, 0x80, 0xC9, 0x04, 0xD0, + 0x95, 0xCC, 0x86, 0xC9, 0x04, 0xD0, 0x95, 0xCC, + 0x88, 0xC9, 0x04, 0xD0, 0x96, 0xCC, 0x86, 0xC9, + 0x04, 0xD0, 0x96, 0xCC, 0x88, 0xC9, 0x04, 0xD0, + 0x97, 0xCC, 0x88, 0xC9, 0x04, 0xD0, 0x98, 0xCC, + 0x80, 0xC9, 0x04, 0xD0, 0x98, 0xCC, 0x84, 0xC9, + 0x04, 0xD0, 0x98, 0xCC, 0x86, 0xC9, 0x04, 0xD0, + // Bytes 3740 - 377f + 0x98, 0xCC, 0x88, 0xC9, 0x04, 0xD0, 0x9A, 0xCC, + 0x81, 0xC9, 0x04, 0xD0, 0x9E, 0xCC, 0x88, 0xC9, + 0x04, 0xD0, 0xA3, 0xCC, 0x84, 0xC9, 0x04, 0xD0, + 0xA3, 0xCC, 0x86, 0xC9, 0x04, 0xD0, 0xA3, 0xCC, + 0x88, 0xC9, 0x04, 0xD0, 0xA3, 0xCC, 0x8B, 0xC9, + 0x04, 0xD0, 0xA7, 0xCC, 0x88, 0xC9, 0x04, 0xD0, + 0xAB, 0xCC, 0x88, 0xC9, 0x04, 0xD0, 0xAD, 0xCC, + 0x88, 0xC9, 0x04, 0xD0, 0xB0, 0xCC, 0x86, 0xC9, + // Bytes 3780 - 37bf + 0x04, 0xD0, 0xB0, 0xCC, 0x88, 0xC9, 0x04, 0xD0, + 0xB3, 0xCC, 0x81, 0xC9, 0x04, 0xD0, 0xB5, 0xCC, + 0x80, 0xC9, 0x04, 0xD0, 0xB5, 0xCC, 0x86, 0xC9, + 0x04, 0xD0, 0xB5, 0xCC, 0x88, 0xC9, 0x04, 0xD0, + 0xB6, 0xCC, 0x86, 0xC9, 0x04, 0xD0, 0xB6, 0xCC, + 0x88, 0xC9, 0x04, 0xD0, 0xB7, 0xCC, 0x88, 0xC9, + 0x04, 0xD0, 0xB8, 0xCC, 0x80, 0xC9, 0x04, 0xD0, + 0xB8, 0xCC, 0x84, 0xC9, 0x04, 0xD0, 0xB8, 0xCC, + // Bytes 37c0 - 37ff + 0x86, 0xC9, 0x04, 0xD0, 0xB8, 0xCC, 0x88, 0xC9, + 0x04, 0xD0, 0xBA, 0xCC, 0x81, 0xC9, 0x04, 0xD0, + 0xBE, 0xCC, 0x88, 0xC9, 0x04, 0xD1, 0x83, 0xCC, + 0x84, 0xC9, 0x04, 0xD1, 0x83, 0xCC, 0x86, 0xC9, + 0x04, 0xD1, 0x83, 0xCC, 0x88, 0xC9, 0x04, 0xD1, + 0x83, 0xCC, 0x8B, 0xC9, 0x04, 0xD1, 0x87, 0xCC, + 0x88, 0xC9, 0x04, 0xD1, 0x8B, 0xCC, 0x88, 0xC9, + 0x04, 0xD1, 0x8D, 0xCC, 0x88, 0xC9, 0x04, 0xD1, + // Bytes 3800 - 383f + 0x96, 0xCC, 0x88, 0xC9, 0x04, 0xD1, 0xB4, 0xCC, + 0x8F, 0xC9, 0x04, 0xD1, 0xB5, 0xCC, 0x8F, 0xC9, + 0x04, 0xD3, 0x98, 0xCC, 0x88, 0xC9, 0x04, 0xD3, + 0x99, 0xCC, 0x88, 0xC9, 0x04, 0xD3, 0xA8, 0xCC, + 0x88, 0xC9, 0x04, 0xD3, 0xA9, 0xCC, 0x88, 0xC9, + 0x04, 0xD8, 0xA7, 0xD9, 0x93, 0xC9, 0x04, 0xD8, + 0xA7, 0xD9, 0x94, 0xC9, 0x04, 0xD8, 0xA7, 0xD9, + 0x95, 0xB5, 0x04, 0xD9, 0x88, 0xD9, 0x94, 0xC9, + // Bytes 3840 - 387f + 0x04, 0xD9, 0x8A, 0xD9, 0x94, 0xC9, 0x04, 0xDB, + 0x81, 0xD9, 0x94, 0xC9, 0x04, 0xDB, 0x92, 0xD9, + 0x94, 0xC9, 0x04, 0xDB, 0x95, 0xD9, 0x94, 0xC9, + 0x05, 0x41, 0xCC, 0x82, 0xCC, 0x80, 0xCA, 0x05, + 0x41, 0xCC, 0x82, 0xCC, 0x81, 0xCA, 0x05, 0x41, + 0xCC, 0x82, 0xCC, 0x83, 0xCA, 0x05, 0x41, 0xCC, + 0x82, 0xCC, 0x89, 0xCA, 0x05, 0x41, 0xCC, 0x86, + 0xCC, 0x80, 0xCA, 0x05, 0x41, 0xCC, 0x86, 0xCC, + // Bytes 3880 - 38bf + 0x81, 0xCA, 0x05, 0x41, 0xCC, 0x86, 0xCC, 0x83, + 0xCA, 0x05, 0x41, 0xCC, 0x86, 0xCC, 0x89, 0xCA, + 0x05, 0x41, 0xCC, 0x87, 0xCC, 0x84, 0xCA, 0x05, + 0x41, 0xCC, 0x88, 0xCC, 0x84, 0xCA, 0x05, 0x41, + 0xCC, 0x8A, 0xCC, 0x81, 0xCA, 0x05, 0x41, 0xCC, + 0xA3, 0xCC, 0x82, 0xCA, 0x05, 0x41, 0xCC, 0xA3, + 0xCC, 0x86, 0xCA, 0x05, 0x43, 0xCC, 0xA7, 0xCC, + 0x81, 0xCA, 0x05, 0x45, 0xCC, 0x82, 0xCC, 0x80, + // Bytes 38c0 - 38ff + 0xCA, 0x05, 0x45, 0xCC, 0x82, 0xCC, 0x81, 0xCA, + 0x05, 0x45, 0xCC, 0x82, 0xCC, 0x83, 0xCA, 0x05, + 0x45, 0xCC, 0x82, 0xCC, 0x89, 0xCA, 0x05, 0x45, + 0xCC, 0x84, 0xCC, 0x80, 0xCA, 0x05, 0x45, 0xCC, + 0x84, 0xCC, 0x81, 0xCA, 0x05, 0x45, 0xCC, 0xA3, + 0xCC, 0x82, 0xCA, 0x05, 0x45, 0xCC, 0xA7, 0xCC, + 0x86, 0xCA, 0x05, 0x49, 0xCC, 0x88, 0xCC, 0x81, + 0xCA, 0x05, 0x4C, 0xCC, 0xA3, 0xCC, 0x84, 0xCA, + // Bytes 3900 - 393f + 0x05, 0x4F, 0xCC, 0x82, 0xCC, 0x80, 0xCA, 0x05, + 0x4F, 0xCC, 0x82, 0xCC, 0x81, 0xCA, 0x05, 0x4F, + 0xCC, 0x82, 0xCC, 0x83, 0xCA, 0x05, 0x4F, 0xCC, + 0x82, 0xCC, 0x89, 0xCA, 0x05, 0x4F, 0xCC, 0x83, + 0xCC, 0x81, 0xCA, 0x05, 0x4F, 0xCC, 0x83, 0xCC, + 0x84, 0xCA, 0x05, 0x4F, 0xCC, 0x83, 0xCC, 0x88, + 0xCA, 0x05, 0x4F, 0xCC, 0x84, 0xCC, 0x80, 0xCA, + 0x05, 0x4F, 0xCC, 0x84, 0xCC, 0x81, 0xCA, 0x05, + // Bytes 3940 - 397f + 0x4F, 0xCC, 0x87, 0xCC, 0x84, 0xCA, 0x05, 0x4F, + 0xCC, 0x88, 0xCC, 0x84, 0xCA, 0x05, 0x4F, 0xCC, + 0x9B, 0xCC, 0x80, 0xCA, 0x05, 0x4F, 0xCC, 0x9B, + 0xCC, 0x81, 0xCA, 0x05, 0x4F, 0xCC, 0x9B, 0xCC, + 0x83, 0xCA, 0x05, 0x4F, 0xCC, 0x9B, 0xCC, 0x89, + 0xCA, 0x05, 0x4F, 0xCC, 0x9B, 0xCC, 0xA3, 0xB6, + 0x05, 0x4F, 0xCC, 0xA3, 0xCC, 0x82, 0xCA, 0x05, + 0x4F, 0xCC, 0xA8, 0xCC, 0x84, 0xCA, 0x05, 0x52, + // Bytes 3980 - 39bf + 0xCC, 0xA3, 0xCC, 0x84, 0xCA, 0x05, 0x53, 0xCC, + 0x81, 0xCC, 0x87, 0xCA, 0x05, 0x53, 0xCC, 0x8C, + 0xCC, 0x87, 0xCA, 0x05, 0x53, 0xCC, 0xA3, 0xCC, + 0x87, 0xCA, 0x05, 0x55, 0xCC, 0x83, 0xCC, 0x81, + 0xCA, 0x05, 0x55, 0xCC, 0x84, 0xCC, 0x88, 0xCA, + 0x05, 0x55, 0xCC, 0x88, 0xCC, 0x80, 0xCA, 0x05, + 0x55, 0xCC, 0x88, 0xCC, 0x81, 0xCA, 0x05, 0x55, + 0xCC, 0x88, 0xCC, 0x84, 0xCA, 0x05, 0x55, 0xCC, + // Bytes 39c0 - 39ff + 0x88, 0xCC, 0x8C, 0xCA, 0x05, 0x55, 0xCC, 0x9B, + 0xCC, 0x80, 0xCA, 0x05, 0x55, 0xCC, 0x9B, 0xCC, + 0x81, 0xCA, 0x05, 0x55, 0xCC, 0x9B, 0xCC, 0x83, + 0xCA, 0x05, 0x55, 0xCC, 0x9B, 0xCC, 0x89, 0xCA, + 0x05, 0x55, 0xCC, 0x9B, 0xCC, 0xA3, 0xB6, 0x05, + 0x61, 0xCC, 0x82, 0xCC, 0x80, 0xCA, 0x05, 0x61, + 0xCC, 0x82, 0xCC, 0x81, 0xCA, 0x05, 0x61, 0xCC, + 0x82, 0xCC, 0x83, 0xCA, 0x05, 0x61, 0xCC, 0x82, + // Bytes 3a00 - 3a3f + 0xCC, 0x89, 0xCA, 0x05, 0x61, 0xCC, 0x86, 0xCC, + 0x80, 0xCA, 0x05, 0x61, 0xCC, 0x86, 0xCC, 0x81, + 0xCA, 0x05, 0x61, 0xCC, 0x86, 0xCC, 0x83, 0xCA, + 0x05, 0x61, 0xCC, 0x86, 0xCC, 0x89, 0xCA, 0x05, + 0x61, 0xCC, 0x87, 0xCC, 0x84, 0xCA, 0x05, 0x61, + 0xCC, 0x88, 0xCC, 0x84, 0xCA, 0x05, 0x61, 0xCC, + 0x8A, 0xCC, 0x81, 0xCA, 0x05, 0x61, 0xCC, 0xA3, + 0xCC, 0x82, 0xCA, 0x05, 0x61, 0xCC, 0xA3, 0xCC, + // Bytes 3a40 - 3a7f + 0x86, 0xCA, 0x05, 0x63, 0xCC, 0xA7, 0xCC, 0x81, + 0xCA, 0x05, 0x65, 0xCC, 0x82, 0xCC, 0x80, 0xCA, + 0x05, 0x65, 0xCC, 0x82, 0xCC, 0x81, 0xCA, 0x05, + 0x65, 0xCC, 0x82, 0xCC, 0x83, 0xCA, 0x05, 0x65, + 0xCC, 0x82, 0xCC, 0x89, 0xCA, 0x05, 0x65, 0xCC, + 0x84, 0xCC, 0x80, 0xCA, 0x05, 0x65, 0xCC, 0x84, + 0xCC, 0x81, 0xCA, 0x05, 0x65, 0xCC, 0xA3, 0xCC, + 0x82, 0xCA, 0x05, 0x65, 0xCC, 0xA7, 0xCC, 0x86, + // Bytes 3a80 - 3abf + 0xCA, 0x05, 0x69, 0xCC, 0x88, 0xCC, 0x81, 0xCA, + 0x05, 0x6C, 0xCC, 0xA3, 0xCC, 0x84, 0xCA, 0x05, + 0x6F, 0xCC, 0x82, 0xCC, 0x80, 0xCA, 0x05, 0x6F, + 0xCC, 0x82, 0xCC, 0x81, 0xCA, 0x05, 0x6F, 0xCC, + 0x82, 0xCC, 0x83, 0xCA, 0x05, 0x6F, 0xCC, 0x82, + 0xCC, 0x89, 0xCA, 0x05, 0x6F, 0xCC, 0x83, 0xCC, + 0x81, 0xCA, 0x05, 0x6F, 0xCC, 0x83, 0xCC, 0x84, + 0xCA, 0x05, 0x6F, 0xCC, 0x83, 0xCC, 0x88, 0xCA, + // Bytes 3ac0 - 3aff + 0x05, 0x6F, 0xCC, 0x84, 0xCC, 0x80, 0xCA, 0x05, + 0x6F, 0xCC, 0x84, 0xCC, 0x81, 0xCA, 0x05, 0x6F, + 0xCC, 0x87, 0xCC, 0x84, 0xCA, 0x05, 0x6F, 0xCC, + 0x88, 0xCC, 0x84, 0xCA, 0x05, 0x6F, 0xCC, 0x9B, + 0xCC, 0x80, 0xCA, 0x05, 0x6F, 0xCC, 0x9B, 0xCC, + 0x81, 0xCA, 0x05, 0x6F, 0xCC, 0x9B, 0xCC, 0x83, + 0xCA, 0x05, 0x6F, 0xCC, 0x9B, 0xCC, 0x89, 0xCA, + 0x05, 0x6F, 0xCC, 0x9B, 0xCC, 0xA3, 0xB6, 0x05, + // Bytes 3b00 - 3b3f + 0x6F, 0xCC, 0xA3, 0xCC, 0x82, 0xCA, 0x05, 0x6F, + 0xCC, 0xA8, 0xCC, 0x84, 0xCA, 0x05, 0x72, 0xCC, + 0xA3, 0xCC, 0x84, 0xCA, 0x05, 0x73, 0xCC, 0x81, + 0xCC, 0x87, 0xCA, 0x05, 0x73, 0xCC, 0x8C, 0xCC, + 0x87, 0xCA, 0x05, 0x73, 0xCC, 0xA3, 0xCC, 0x87, + 0xCA, 0x05, 0x75, 0xCC, 0x83, 0xCC, 0x81, 0xCA, + 0x05, 0x75, 0xCC, 0x84, 0xCC, 0x88, 0xCA, 0x05, + 0x75, 0xCC, 0x88, 0xCC, 0x80, 0xCA, 0x05, 0x75, + // Bytes 3b40 - 3b7f + 0xCC, 0x88, 0xCC, 0x81, 0xCA, 0x05, 0x75, 0xCC, + 0x88, 0xCC, 0x84, 0xCA, 0x05, 0x75, 0xCC, 0x88, + 0xCC, 0x8C, 0xCA, 0x05, 0x75, 0xCC, 0x9B, 0xCC, + 0x80, 0xCA, 0x05, 0x75, 0xCC, 0x9B, 0xCC, 0x81, + 0xCA, 0x05, 0x75, 0xCC, 0x9B, 0xCC, 0x83, 0xCA, + 0x05, 0x75, 0xCC, 0x9B, 0xCC, 0x89, 0xCA, 0x05, + 0x75, 0xCC, 0x9B, 0xCC, 0xA3, 0xB6, 0x05, 0xE1, + 0xBE, 0xBF, 0xCC, 0x80, 0xCA, 0x05, 0xE1, 0xBE, + // Bytes 3b80 - 3bbf + 0xBF, 0xCC, 0x81, 0xCA, 0x05, 0xE1, 0xBE, 0xBF, + 0xCD, 0x82, 0xCA, 0x05, 0xE1, 0xBF, 0xBE, 0xCC, + 0x80, 0xCA, 0x05, 0xE1, 0xBF, 0xBE, 0xCC, 0x81, + 0xCA, 0x05, 0xE1, 0xBF, 0xBE, 0xCD, 0x82, 0xCA, + 0x05, 0xE2, 0x86, 0x90, 0xCC, 0xB8, 0x05, 0x05, + 0xE2, 0x86, 0x92, 0xCC, 0xB8, 0x05, 0x05, 0xE2, + 0x86, 0x94, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x87, + 0x90, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x87, 0x92, + // Bytes 3bc0 - 3bff + 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x87, 0x94, 0xCC, + 0xB8, 0x05, 0x05, 0xE2, 0x88, 0x83, 0xCC, 0xB8, + 0x05, 0x05, 0xE2, 0x88, 0x88, 0xCC, 0xB8, 0x05, + 0x05, 0xE2, 0x88, 0x8B, 0xCC, 0xB8, 0x05, 0x05, + 0xE2, 0x88, 0xA3, 0xCC, 0xB8, 0x05, 0x05, 0xE2, + 0x88, 0xA5, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x88, + 0xBC, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x89, 0x83, + 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x89, 0x85, 0xCC, + // Bytes 3c00 - 3c3f + 0xB8, 0x05, 0x05, 0xE2, 0x89, 0x88, 0xCC, 0xB8, + 0x05, 0x05, 0xE2, 0x89, 0x8D, 0xCC, 0xB8, 0x05, + 0x05, 0xE2, 0x89, 0xA1, 0xCC, 0xB8, 0x05, 0x05, + 0xE2, 0x89, 0xA4, 0xCC, 0xB8, 0x05, 0x05, 0xE2, + 0x89, 0xA5, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x89, + 0xB2, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x89, 0xB3, + 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x89, 0xB6, 0xCC, + 0xB8, 0x05, 0x05, 0xE2, 0x89, 0xB7, 0xCC, 0xB8, + // Bytes 3c40 - 3c7f + 0x05, 0x05, 0xE2, 0x89, 0xBA, 0xCC, 0xB8, 0x05, + 0x05, 0xE2, 0x89, 0xBB, 0xCC, 0xB8, 0x05, 0x05, + 0xE2, 0x89, 0xBC, 0xCC, 0xB8, 0x05, 0x05, 0xE2, + 0x89, 0xBD, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x8A, + 0x82, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x8A, 0x83, + 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x8A, 0x86, 0xCC, + 0xB8, 0x05, 0x05, 0xE2, 0x8A, 0x87, 0xCC, 0xB8, + 0x05, 0x05, 0xE2, 0x8A, 0x91, 0xCC, 0xB8, 0x05, + // Bytes 3c80 - 3cbf + 0x05, 0xE2, 0x8A, 0x92, 0xCC, 0xB8, 0x05, 0x05, + 0xE2, 0x8A, 0xA2, 0xCC, 0xB8, 0x05, 0x05, 0xE2, + 0x8A, 0xA8, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x8A, + 0xA9, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x8A, 0xAB, + 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x8A, 0xB2, 0xCC, + 0xB8, 0x05, 0x05, 0xE2, 0x8A, 0xB3, 0xCC, 0xB8, + 0x05, 0x05, 0xE2, 0x8A, 0xB4, 0xCC, 0xB8, 0x05, + 0x05, 0xE2, 0x8A, 0xB5, 0xCC, 0xB8, 0x05, 0x06, + // Bytes 3cc0 - 3cff + 0xCE, 0x91, 0xCC, 0x93, 0xCD, 0x85, 0xDA, 0x06, + 0xCE, 0x91, 0xCC, 0x94, 0xCD, 0x85, 0xDA, 0x06, + 0xCE, 0x95, 0xCC, 0x93, 0xCC, 0x80, 0xCA, 0x06, + 0xCE, 0x95, 0xCC, 0x93, 0xCC, 0x81, 0xCA, 0x06, + 0xCE, 0x95, 0xCC, 0x94, 0xCC, 0x80, 0xCA, 0x06, + 0xCE, 0x95, 0xCC, 0x94, 0xCC, 0x81, 0xCA, 0x06, + 0xCE, 0x97, 0xCC, 0x93, 0xCD, 0x85, 0xDA, 0x06, + 0xCE, 0x97, 0xCC, 0x94, 0xCD, 0x85, 0xDA, 0x06, + // Bytes 3d00 - 3d3f + 0xCE, 0x99, 0xCC, 0x93, 0xCC, 0x80, 0xCA, 0x06, + 0xCE, 0x99, 0xCC, 0x93, 0xCC, 0x81, 0xCA, 0x06, + 0xCE, 0x99, 0xCC, 0x93, 0xCD, 0x82, 0xCA, 0x06, + 0xCE, 0x99, 0xCC, 0x94, 0xCC, 0x80, 0xCA, 0x06, + 0xCE, 0x99, 0xCC, 0x94, 0xCC, 0x81, 0xCA, 0x06, + 0xCE, 0x99, 0xCC, 0x94, 0xCD, 0x82, 0xCA, 0x06, + 0xCE, 0x9F, 0xCC, 0x93, 0xCC, 0x80, 0xCA, 0x06, + 0xCE, 0x9F, 0xCC, 0x93, 0xCC, 0x81, 0xCA, 0x06, + // Bytes 3d40 - 3d7f + 0xCE, 0x9F, 0xCC, 0x94, 0xCC, 0x80, 0xCA, 0x06, + 0xCE, 0x9F, 0xCC, 0x94, 0xCC, 0x81, 0xCA, 0x06, + 0xCE, 0xA5, 0xCC, 0x94, 0xCC, 0x80, 0xCA, 0x06, + 0xCE, 0xA5, 0xCC, 0x94, 0xCC, 0x81, 0xCA, 0x06, + 0xCE, 0xA5, 0xCC, 0x94, 0xCD, 0x82, 0xCA, 0x06, + 0xCE, 0xA9, 0xCC, 0x93, 0xCD, 0x85, 0xDA, 0x06, + 0xCE, 0xA9, 0xCC, 0x94, 0xCD, 0x85, 0xDA, 0x06, + 0xCE, 0xB1, 0xCC, 0x80, 0xCD, 0x85, 0xDA, 0x06, + // Bytes 3d80 - 3dbf + 0xCE, 0xB1, 0xCC, 0x81, 0xCD, 0x85, 0xDA, 0x06, + 0xCE, 0xB1, 0xCC, 0x93, 0xCD, 0x85, 0xDA, 0x06, + 0xCE, 0xB1, 0xCC, 0x94, 0xCD, 0x85, 0xDA, 0x06, + 0xCE, 0xB1, 0xCD, 0x82, 0xCD, 0x85, 0xDA, 0x06, + 0xCE, 0xB5, 0xCC, 0x93, 0xCC, 0x80, 0xCA, 0x06, + 0xCE, 0xB5, 0xCC, 0x93, 0xCC, 0x81, 0xCA, 0x06, + 0xCE, 0xB5, 0xCC, 0x94, 0xCC, 0x80, 0xCA, 0x06, + 0xCE, 0xB5, 0xCC, 0x94, 0xCC, 0x81, 0xCA, 0x06, + // Bytes 3dc0 - 3dff + 0xCE, 0xB7, 0xCC, 0x80, 0xCD, 0x85, 0xDA, 0x06, + 0xCE, 0xB7, 0xCC, 0x81, 0xCD, 0x85, 0xDA, 0x06, + 0xCE, 0xB7, 0xCC, 0x93, 0xCD, 0x85, 0xDA, 0x06, + 0xCE, 0xB7, 0xCC, 0x94, 0xCD, 0x85, 0xDA, 0x06, + 0xCE, 0xB7, 0xCD, 0x82, 0xCD, 0x85, 0xDA, 0x06, + 0xCE, 0xB9, 0xCC, 0x88, 0xCC, 0x80, 0xCA, 0x06, + 0xCE, 0xB9, 0xCC, 0x88, 0xCC, 0x81, 0xCA, 0x06, + 0xCE, 0xB9, 0xCC, 0x88, 0xCD, 0x82, 0xCA, 0x06, + // Bytes 3e00 - 3e3f + 0xCE, 0xB9, 0xCC, 0x93, 0xCC, 0x80, 0xCA, 0x06, + 0xCE, 0xB9, 0xCC, 0x93, 0xCC, 0x81, 0xCA, 0x06, + 0xCE, 0xB9, 0xCC, 0x93, 0xCD, 0x82, 0xCA, 0x06, + 0xCE, 0xB9, 0xCC, 0x94, 0xCC, 0x80, 0xCA, 0x06, + 0xCE, 0xB9, 0xCC, 0x94, 0xCC, 0x81, 0xCA, 0x06, + 0xCE, 0xB9, 0xCC, 0x94, 0xCD, 0x82, 0xCA, 0x06, + 0xCE, 0xBF, 0xCC, 0x93, 0xCC, 0x80, 0xCA, 0x06, + 0xCE, 0xBF, 0xCC, 0x93, 0xCC, 0x81, 0xCA, 0x06, + // Bytes 3e40 - 3e7f + 0xCE, 0xBF, 0xCC, 0x94, 0xCC, 0x80, 0xCA, 0x06, + 0xCE, 0xBF, 0xCC, 0x94, 0xCC, 0x81, 0xCA, 0x06, + 0xCF, 0x85, 0xCC, 0x88, 0xCC, 0x80, 0xCA, 0x06, + 0xCF, 0x85, 0xCC, 0x88, 0xCC, 0x81, 0xCA, 0x06, + 0xCF, 0x85, 0xCC, 0x88, 0xCD, 0x82, 0xCA, 0x06, + 0xCF, 0x85, 0xCC, 0x93, 0xCC, 0x80, 0xCA, 0x06, + 0xCF, 0x85, 0xCC, 0x93, 0xCC, 0x81, 0xCA, 0x06, + 0xCF, 0x85, 0xCC, 0x93, 0xCD, 0x82, 0xCA, 0x06, + // Bytes 3e80 - 3ebf + 0xCF, 0x85, 0xCC, 0x94, 0xCC, 0x80, 0xCA, 0x06, + 0xCF, 0x85, 0xCC, 0x94, 0xCC, 0x81, 0xCA, 0x06, + 0xCF, 0x85, 0xCC, 0x94, 0xCD, 0x82, 0xCA, 0x06, + 0xCF, 0x89, 0xCC, 0x80, 0xCD, 0x85, 0xDA, 0x06, + 0xCF, 0x89, 0xCC, 0x81, 0xCD, 0x85, 0xDA, 0x06, + 0xCF, 0x89, 0xCC, 0x93, 0xCD, 0x85, 0xDA, 0x06, + 0xCF, 0x89, 0xCC, 0x94, 0xCD, 0x85, 0xDA, 0x06, + 0xCF, 0x89, 0xCD, 0x82, 0xCD, 0x85, 0xDA, 0x06, + // Bytes 3ec0 - 3eff + 0xE0, 0xA4, 0xA8, 0xE0, 0xA4, 0xBC, 0x09, 0x06, + 0xE0, 0xA4, 0xB0, 0xE0, 0xA4, 0xBC, 0x09, 0x06, + 0xE0, 0xA4, 0xB3, 0xE0, 0xA4, 0xBC, 0x09, 0x06, + 0xE0, 0xB1, 0x86, 0xE0, 0xB1, 0x96, 0x85, 0x06, + 0xE0, 0xB7, 0x99, 0xE0, 0xB7, 0x8A, 0x11, 0x06, + 0xE3, 0x81, 0x86, 0xE3, 0x82, 0x99, 0x0D, 0x06, + 0xE3, 0x81, 0x8B, 0xE3, 0x82, 0x99, 0x0D, 0x06, + 0xE3, 0x81, 0x8D, 0xE3, 0x82, 0x99, 0x0D, 0x06, + // Bytes 3f00 - 3f3f + 0xE3, 0x81, 0x8F, 0xE3, 0x82, 0x99, 0x0D, 0x06, + 0xE3, 0x81, 0x91, 0xE3, 0x82, 0x99, 0x0D, 0x06, + 0xE3, 0x81, 0x93, 0xE3, 0x82, 0x99, 0x0D, 0x06, + 0xE3, 0x81, 0x95, 0xE3, 0x82, 0x99, 0x0D, 0x06, + 0xE3, 0x81, 0x97, 0xE3, 0x82, 0x99, 0x0D, 0x06, + 0xE3, 0x81, 0x99, 0xE3, 0x82, 0x99, 0x0D, 0x06, + 0xE3, 0x81, 0x9B, 0xE3, 0x82, 0x99, 0x0D, 0x06, + 0xE3, 0x81, 0x9D, 0xE3, 0x82, 0x99, 0x0D, 0x06, + // Bytes 3f40 - 3f7f + 0xE3, 0x81, 0x9F, 0xE3, 0x82, 0x99, 0x0D, 0x06, + 0xE3, 0x81, 0xA1, 0xE3, 0x82, 0x99, 0x0D, 0x06, + 0xE3, 0x81, 0xA4, 0xE3, 0x82, 0x99, 0x0D, 0x06, + 0xE3, 0x81, 0xA6, 0xE3, 0x82, 0x99, 0x0D, 0x06, + 0xE3, 0x81, 0xA8, 0xE3, 0x82, 0x99, 0x0D, 0x06, + 0xE3, 0x81, 0xAF, 0xE3, 0x82, 0x99, 0x0D, 0x06, + 0xE3, 0x81, 0xAF, 0xE3, 0x82, 0x9A, 0x0D, 0x06, + 0xE3, 0x81, 0xB2, 0xE3, 0x82, 0x99, 0x0D, 0x06, + // Bytes 3f80 - 3fbf + 0xE3, 0x81, 0xB2, 0xE3, 0x82, 0x9A, 0x0D, 0x06, + 0xE3, 0x81, 0xB5, 0xE3, 0x82, 0x99, 0x0D, 0x06, + 0xE3, 0x81, 0xB5, 0xE3, 0x82, 0x9A, 0x0D, 0x06, + 0xE3, 0x81, 0xB8, 0xE3, 0x82, 0x99, 0x0D, 0x06, + 0xE3, 0x81, 0xB8, 0xE3, 0x82, 0x9A, 0x0D, 0x06, + 0xE3, 0x81, 0xBB, 0xE3, 0x82, 0x99, 0x0D, 0x06, + 0xE3, 0x81, 0xBB, 0xE3, 0x82, 0x9A, 0x0D, 0x06, + 0xE3, 0x82, 0x9D, 0xE3, 0x82, 0x99, 0x0D, 0x06, + // Bytes 3fc0 - 3fff + 0xE3, 0x82, 0xA6, 0xE3, 0x82, 0x99, 0x0D, 0x06, + 0xE3, 0x82, 0xAB, 0xE3, 0x82, 0x99, 0x0D, 0x06, + 0xE3, 0x82, 0xAD, 0xE3, 0x82, 0x99, 0x0D, 0x06, + 0xE3, 0x82, 0xAF, 0xE3, 0x82, 0x99, 0x0D, 0x06, + 0xE3, 0x82, 0xB1, 0xE3, 0x82, 0x99, 0x0D, 0x06, + 0xE3, 0x82, 0xB3, 0xE3, 0x82, 0x99, 0x0D, 0x06, + 0xE3, 0x82, 0xB5, 0xE3, 0x82, 0x99, 0x0D, 0x06, + 0xE3, 0x82, 0xB7, 0xE3, 0x82, 0x99, 0x0D, 0x06, + // Bytes 4000 - 403f + 0xE3, 0x82, 0xB9, 0xE3, 0x82, 0x99, 0x0D, 0x06, + 0xE3, 0x82, 0xBB, 0xE3, 0x82, 0x99, 0x0D, 0x06, + 0xE3, 0x82, 0xBD, 0xE3, 0x82, 0x99, 0x0D, 0x06, + 0xE3, 0x82, 0xBF, 0xE3, 0x82, 0x99, 0x0D, 0x06, + 0xE3, 0x83, 0x81, 0xE3, 0x82, 0x99, 0x0D, 0x06, + 0xE3, 0x83, 0x84, 0xE3, 0x82, 0x99, 0x0D, 0x06, + 0xE3, 0x83, 0x86, 0xE3, 0x82, 0x99, 0x0D, 0x06, + 0xE3, 0x83, 0x88, 0xE3, 0x82, 0x99, 0x0D, 0x06, + // Bytes 4040 - 407f + 0xE3, 0x83, 0x8F, 0xE3, 0x82, 0x99, 0x0D, 0x06, + 0xE3, 0x83, 0x8F, 0xE3, 0x82, 0x9A, 0x0D, 0x06, + 0xE3, 0x83, 0x92, 0xE3, 0x82, 0x99, 0x0D, 0x06, + 0xE3, 0x83, 0x92, 0xE3, 0x82, 0x9A, 0x0D, 0x06, + 0xE3, 0x83, 0x95, 0xE3, 0x82, 0x99, 0x0D, 0x06, + 0xE3, 0x83, 0x95, 0xE3, 0x82, 0x9A, 0x0D, 0x06, + 0xE3, 0x83, 0x98, 0xE3, 0x82, 0x99, 0x0D, 0x06, + 0xE3, 0x83, 0x98, 0xE3, 0x82, 0x9A, 0x0D, 0x06, + // Bytes 4080 - 40bf + 0xE3, 0x83, 0x9B, 0xE3, 0x82, 0x99, 0x0D, 0x06, + 0xE3, 0x83, 0x9B, 0xE3, 0x82, 0x9A, 0x0D, 0x06, + 0xE3, 0x83, 0xAF, 0xE3, 0x82, 0x99, 0x0D, 0x06, + 0xE3, 0x83, 0xB0, 0xE3, 0x82, 0x99, 0x0D, 0x06, + 0xE3, 0x83, 0xB1, 0xE3, 0x82, 0x99, 0x0D, 0x06, + 0xE3, 0x83, 0xB2, 0xE3, 0x82, 0x99, 0x0D, 0x06, + 0xE3, 0x83, 0xBD, 0xE3, 0x82, 0x99, 0x0D, 0x08, + 0xCE, 0x91, 0xCC, 0x93, 0xCC, 0x80, 0xCD, 0x85, + // Bytes 40c0 - 40ff + 0xDB, 0x08, 0xCE, 0x91, 0xCC, 0x93, 0xCC, 0x81, + 0xCD, 0x85, 0xDB, 0x08, 0xCE, 0x91, 0xCC, 0x93, + 0xCD, 0x82, 0xCD, 0x85, 0xDB, 0x08, 0xCE, 0x91, + 0xCC, 0x94, 0xCC, 0x80, 0xCD, 0x85, 0xDB, 0x08, + 0xCE, 0x91, 0xCC, 0x94, 0xCC, 0x81, 0xCD, 0x85, + 0xDB, 0x08, 0xCE, 0x91, 0xCC, 0x94, 0xCD, 0x82, + 0xCD, 0x85, 0xDB, 0x08, 0xCE, 0x97, 0xCC, 0x93, + 0xCC, 0x80, 0xCD, 0x85, 0xDB, 0x08, 0xCE, 0x97, + // Bytes 4100 - 413f + 0xCC, 0x93, 0xCC, 0x81, 0xCD, 0x85, 0xDB, 0x08, + 0xCE, 0x97, 0xCC, 0x93, 0xCD, 0x82, 0xCD, 0x85, + 0xDB, 0x08, 0xCE, 0x97, 0xCC, 0x94, 0xCC, 0x80, + 0xCD, 0x85, 0xDB, 0x08, 0xCE, 0x97, 0xCC, 0x94, + 0xCC, 0x81, 0xCD, 0x85, 0xDB, 0x08, 0xCE, 0x97, + 0xCC, 0x94, 0xCD, 0x82, 0xCD, 0x85, 0xDB, 0x08, + 0xCE, 0xA9, 0xCC, 0x93, 0xCC, 0x80, 0xCD, 0x85, + 0xDB, 0x08, 0xCE, 0xA9, 0xCC, 0x93, 0xCC, 0x81, + // Bytes 4140 - 417f + 0xCD, 0x85, 0xDB, 0x08, 0xCE, 0xA9, 0xCC, 0x93, + 0xCD, 0x82, 0xCD, 0x85, 0xDB, 0x08, 0xCE, 0xA9, + 0xCC, 0x94, 0xCC, 0x80, 0xCD, 0x85, 0xDB, 0x08, + 0xCE, 0xA9, 0xCC, 0x94, 0xCC, 0x81, 0xCD, 0x85, + 0xDB, 0x08, 0xCE, 0xA9, 0xCC, 0x94, 0xCD, 0x82, + 0xCD, 0x85, 0xDB, 0x08, 0xCE, 0xB1, 0xCC, 0x93, + 0xCC, 0x80, 0xCD, 0x85, 0xDB, 0x08, 0xCE, 0xB1, + 0xCC, 0x93, 0xCC, 0x81, 0xCD, 0x85, 0xDB, 0x08, + // Bytes 4180 - 41bf + 0xCE, 0xB1, 0xCC, 0x93, 0xCD, 0x82, 0xCD, 0x85, + 0xDB, 0x08, 0xCE, 0xB1, 0xCC, 0x94, 0xCC, 0x80, + 0xCD, 0x85, 0xDB, 0x08, 0xCE, 0xB1, 0xCC, 0x94, + 0xCC, 0x81, 0xCD, 0x85, 0xDB, 0x08, 0xCE, 0xB1, + 0xCC, 0x94, 0xCD, 0x82, 0xCD, 0x85, 0xDB, 0x08, + 0xCE, 0xB7, 0xCC, 0x93, 0xCC, 0x80, 0xCD, 0x85, + 0xDB, 0x08, 0xCE, 0xB7, 0xCC, 0x93, 0xCC, 0x81, + 0xCD, 0x85, 0xDB, 0x08, 0xCE, 0xB7, 0xCC, 0x93, + // Bytes 41c0 - 41ff + 0xCD, 0x82, 0xCD, 0x85, 0xDB, 0x08, 0xCE, 0xB7, + 0xCC, 0x94, 0xCC, 0x80, 0xCD, 0x85, 0xDB, 0x08, + 0xCE, 0xB7, 0xCC, 0x94, 0xCC, 0x81, 0xCD, 0x85, + 0xDB, 0x08, 0xCE, 0xB7, 0xCC, 0x94, 0xCD, 0x82, + 0xCD, 0x85, 0xDB, 0x08, 0xCF, 0x89, 0xCC, 0x93, + 0xCC, 0x80, 0xCD, 0x85, 0xDB, 0x08, 0xCF, 0x89, + 0xCC, 0x93, 0xCC, 0x81, 0xCD, 0x85, 0xDB, 0x08, + 0xCF, 0x89, 0xCC, 0x93, 0xCD, 0x82, 0xCD, 0x85, + // Bytes 4200 - 423f + 0xDB, 0x08, 0xCF, 0x89, 0xCC, 0x94, 0xCC, 0x80, + 0xCD, 0x85, 0xDB, 0x08, 0xCF, 0x89, 0xCC, 0x94, + 0xCC, 0x81, 0xCD, 0x85, 0xDB, 0x08, 0xCF, 0x89, + 0xCC, 0x94, 0xCD, 0x82, 0xCD, 0x85, 0xDB, 0x08, + 0xF0, 0x91, 0x82, 0x99, 0xF0, 0x91, 0x82, 0xBA, + 0x09, 0x08, 0xF0, 0x91, 0x82, 0x9B, 0xF0, 0x91, + 0x82, 0xBA, 0x09, 0x08, 0xF0, 0x91, 0x82, 0xA5, + 0xF0, 0x91, 0x82, 0xBA, 0x09, 0x42, 0xC2, 0xB4, + // Bytes 4240 - 427f + 0x01, 0x43, 0x20, 0xCC, 0x81, 0xC9, 0x43, 0x20, + 0xCC, 0x83, 0xC9, 0x43, 0x20, 0xCC, 0x84, 0xC9, + 0x43, 0x20, 0xCC, 0x85, 0xC9, 0x43, 0x20, 0xCC, + 0x86, 0xC9, 0x43, 0x20, 0xCC, 0x87, 0xC9, 0x43, + 0x20, 0xCC, 0x88, 0xC9, 0x43, 0x20, 0xCC, 0x8A, + 0xC9, 0x43, 0x20, 0xCC, 0x8B, 0xC9, 0x43, 0x20, + 0xCC, 0x93, 0xC9, 0x43, 0x20, 0xCC, 0x94, 0xC9, + 0x43, 0x20, 0xCC, 0xA7, 0xA5, 0x43, 0x20, 0xCC, + // Bytes 4280 - 42bf + 0xA8, 0xA5, 0x43, 0x20, 0xCC, 0xB3, 0xB5, 0x43, + 0x20, 0xCD, 0x82, 0xC9, 0x43, 0x20, 0xCD, 0x85, + 0xD9, 0x43, 0x20, 0xD9, 0x8B, 0x59, 0x43, 0x20, + 0xD9, 0x8C, 0x5D, 0x43, 0x20, 0xD9, 0x8D, 0x61, + 0x43, 0x20, 0xD9, 0x8E, 0x65, 0x43, 0x20, 0xD9, + 0x8F, 0x69, 0x43, 0x20, 0xD9, 0x90, 0x6D, 0x43, + 0x20, 0xD9, 0x91, 0x71, 0x43, 0x20, 0xD9, 0x92, + 0x75, 0x43, 0x41, 0xCC, 0x8A, 0xC9, 0x43, 0x73, + // Bytes 42c0 - 42ff + 0xCC, 0x87, 0xC9, 0x44, 0x20, 0xE3, 0x82, 0x99, + 0x0D, 0x44, 0x20, 0xE3, 0x82, 0x9A, 0x0D, 0x44, + 0xC2, 0xA8, 0xCC, 0x81, 0xCA, 0x44, 0xCE, 0x91, + 0xCC, 0x81, 0xC9, 0x44, 0xCE, 0x95, 0xCC, 0x81, + 0xC9, 0x44, 0xCE, 0x97, 0xCC, 0x81, 0xC9, 0x44, + 0xCE, 0x99, 0xCC, 0x81, 0xC9, 0x44, 0xCE, 0x9F, + 0xCC, 0x81, 0xC9, 0x44, 0xCE, 0xA5, 0xCC, 0x81, + 0xC9, 0x44, 0xCE, 0xA5, 0xCC, 0x88, 0xC9, 0x44, + // Bytes 4300 - 433f + 0xCE, 0xA9, 0xCC, 0x81, 0xC9, 0x44, 0xCE, 0xB1, + 0xCC, 0x81, 0xC9, 0x44, 0xCE, 0xB5, 0xCC, 0x81, + 0xC9, 0x44, 0xCE, 0xB7, 0xCC, 0x81, 0xC9, 0x44, + 0xCE, 0xB9, 0xCC, 0x81, 0xC9, 0x44, 0xCE, 0xBF, + 0xCC, 0x81, 0xC9, 0x44, 0xCF, 0x85, 0xCC, 0x81, + 0xC9, 0x44, 0xCF, 0x89, 0xCC, 0x81, 0xC9, 0x44, + 0xD7, 0x90, 0xD6, 0xB7, 0x31, 0x44, 0xD7, 0x90, + 0xD6, 0xB8, 0x35, 0x44, 0xD7, 0x90, 0xD6, 0xBC, + // Bytes 4340 - 437f + 0x41, 0x44, 0xD7, 0x91, 0xD6, 0xBC, 0x41, 0x44, + 0xD7, 0x91, 0xD6, 0xBF, 0x49, 0x44, 0xD7, 0x92, + 0xD6, 0xBC, 0x41, 0x44, 0xD7, 0x93, 0xD6, 0xBC, + 0x41, 0x44, 0xD7, 0x94, 0xD6, 0xBC, 0x41, 0x44, + 0xD7, 0x95, 0xD6, 0xB9, 0x39, 0x44, 0xD7, 0x95, + 0xD6, 0xBC, 0x41, 0x44, 0xD7, 0x96, 0xD6, 0xBC, + 0x41, 0x44, 0xD7, 0x98, 0xD6, 0xBC, 0x41, 0x44, + 0xD7, 0x99, 0xD6, 0xB4, 0x25, 0x44, 0xD7, 0x99, + // Bytes 4380 - 43bf + 0xD6, 0xBC, 0x41, 0x44, 0xD7, 0x9A, 0xD6, 0xBC, + 0x41, 0x44, 0xD7, 0x9B, 0xD6, 0xBC, 0x41, 0x44, + 0xD7, 0x9B, 0xD6, 0xBF, 0x49, 0x44, 0xD7, 0x9C, + 0xD6, 0xBC, 0x41, 0x44, 0xD7, 0x9E, 0xD6, 0xBC, + 0x41, 0x44, 0xD7, 0xA0, 0xD6, 0xBC, 0x41, 0x44, + 0xD7, 0xA1, 0xD6, 0xBC, 0x41, 0x44, 0xD7, 0xA3, + 0xD6, 0xBC, 0x41, 0x44, 0xD7, 0xA4, 0xD6, 0xBC, + 0x41, 0x44, 0xD7, 0xA4, 0xD6, 0xBF, 0x49, 0x44, + // Bytes 43c0 - 43ff + 0xD7, 0xA6, 0xD6, 0xBC, 0x41, 0x44, 0xD7, 0xA7, + 0xD6, 0xBC, 0x41, 0x44, 0xD7, 0xA8, 0xD6, 0xBC, + 0x41, 0x44, 0xD7, 0xA9, 0xD6, 0xBC, 0x41, 0x44, + 0xD7, 0xA9, 0xD7, 0x81, 0x4D, 0x44, 0xD7, 0xA9, + 0xD7, 0x82, 0x51, 0x44, 0xD7, 0xAA, 0xD6, 0xBC, + 0x41, 0x44, 0xD7, 0xB2, 0xD6, 0xB7, 0x31, 0x44, + 0xD8, 0xA7, 0xD9, 0x8B, 0x59, 0x44, 0xD8, 0xA7, + 0xD9, 0x93, 0xC9, 0x44, 0xD8, 0xA7, 0xD9, 0x94, + // Bytes 4400 - 443f + 0xC9, 0x44, 0xD8, 0xA7, 0xD9, 0x95, 0xB5, 0x44, + 0xD8, 0xB0, 0xD9, 0xB0, 0x79, 0x44, 0xD8, 0xB1, + 0xD9, 0xB0, 0x79, 0x44, 0xD9, 0x80, 0xD9, 0x8B, + 0x59, 0x44, 0xD9, 0x80, 0xD9, 0x8E, 0x65, 0x44, + 0xD9, 0x80, 0xD9, 0x8F, 0x69, 0x44, 0xD9, 0x80, + 0xD9, 0x90, 0x6D, 0x44, 0xD9, 0x80, 0xD9, 0x91, + 0x71, 0x44, 0xD9, 0x80, 0xD9, 0x92, 0x75, 0x44, + 0xD9, 0x87, 0xD9, 0xB0, 0x79, 0x44, 0xD9, 0x88, + // Bytes 4440 - 447f + 0xD9, 0x94, 0xC9, 0x44, 0xD9, 0x89, 0xD9, 0xB0, + 0x79, 0x44, 0xD9, 0x8A, 0xD9, 0x94, 0xC9, 0x44, + 0xDB, 0x92, 0xD9, 0x94, 0xC9, 0x44, 0xDB, 0x95, + 0xD9, 0x94, 0xC9, 0x45, 0x20, 0xCC, 0x88, 0xCC, + 0x80, 0xCA, 0x45, 0x20, 0xCC, 0x88, 0xCC, 0x81, + 0xCA, 0x45, 0x20, 0xCC, 0x88, 0xCD, 0x82, 0xCA, + 0x45, 0x20, 0xCC, 0x93, 0xCC, 0x80, 0xCA, 0x45, + 0x20, 0xCC, 0x93, 0xCC, 0x81, 0xCA, 0x45, 0x20, + // Bytes 4480 - 44bf + 0xCC, 0x93, 0xCD, 0x82, 0xCA, 0x45, 0x20, 0xCC, + 0x94, 0xCC, 0x80, 0xCA, 0x45, 0x20, 0xCC, 0x94, + 0xCC, 0x81, 0xCA, 0x45, 0x20, 0xCC, 0x94, 0xCD, + 0x82, 0xCA, 0x45, 0x20, 0xD9, 0x8C, 0xD9, 0x91, + 0x72, 0x45, 0x20, 0xD9, 0x8D, 0xD9, 0x91, 0x72, + 0x45, 0x20, 0xD9, 0x8E, 0xD9, 0x91, 0x72, 0x45, + 0x20, 0xD9, 0x8F, 0xD9, 0x91, 0x72, 0x45, 0x20, + 0xD9, 0x90, 0xD9, 0x91, 0x72, 0x45, 0x20, 0xD9, + // Bytes 44c0 - 44ff + 0x91, 0xD9, 0xB0, 0x7A, 0x45, 0xE2, 0xAB, 0x9D, + 0xCC, 0xB8, 0x05, 0x46, 0xCE, 0xB9, 0xCC, 0x88, + 0xCC, 0x81, 0xCA, 0x46, 0xCF, 0x85, 0xCC, 0x88, + 0xCC, 0x81, 0xCA, 0x46, 0xD7, 0xA9, 0xD6, 0xBC, + 0xD7, 0x81, 0x4E, 0x46, 0xD7, 0xA9, 0xD6, 0xBC, + 0xD7, 0x82, 0x52, 0x46, 0xD9, 0x80, 0xD9, 0x8E, + 0xD9, 0x91, 0x72, 0x46, 0xD9, 0x80, 0xD9, 0x8F, + 0xD9, 0x91, 0x72, 0x46, 0xD9, 0x80, 0xD9, 0x90, + // Bytes 4500 - 453f + 0xD9, 0x91, 0x72, 0x46, 0xE0, 0xA4, 0x95, 0xE0, + 0xA4, 0xBC, 0x09, 0x46, 0xE0, 0xA4, 0x96, 0xE0, + 0xA4, 0xBC, 0x09, 0x46, 0xE0, 0xA4, 0x97, 0xE0, + 0xA4, 0xBC, 0x09, 0x46, 0xE0, 0xA4, 0x9C, 0xE0, + 0xA4, 0xBC, 0x09, 0x46, 0xE0, 0xA4, 0xA1, 0xE0, + 0xA4, 0xBC, 0x09, 0x46, 0xE0, 0xA4, 0xA2, 0xE0, + 0xA4, 0xBC, 0x09, 0x46, 0xE0, 0xA4, 0xAB, 0xE0, + 0xA4, 0xBC, 0x09, 0x46, 0xE0, 0xA4, 0xAF, 0xE0, + // Bytes 4540 - 457f + 0xA4, 0xBC, 0x09, 0x46, 0xE0, 0xA6, 0xA1, 0xE0, + 0xA6, 0xBC, 0x09, 0x46, 0xE0, 0xA6, 0xA2, 0xE0, + 0xA6, 0xBC, 0x09, 0x46, 0xE0, 0xA6, 0xAF, 0xE0, + 0xA6, 0xBC, 0x09, 0x46, 0xE0, 0xA8, 0x96, 0xE0, + 0xA8, 0xBC, 0x09, 0x46, 0xE0, 0xA8, 0x97, 0xE0, + 0xA8, 0xBC, 0x09, 0x46, 0xE0, 0xA8, 0x9C, 0xE0, + 0xA8, 0xBC, 0x09, 0x46, 0xE0, 0xA8, 0xAB, 0xE0, + 0xA8, 0xBC, 0x09, 0x46, 0xE0, 0xA8, 0xB2, 0xE0, + // Bytes 4580 - 45bf + 0xA8, 0xBC, 0x09, 0x46, 0xE0, 0xA8, 0xB8, 0xE0, + 0xA8, 0xBC, 0x09, 0x46, 0xE0, 0xAC, 0xA1, 0xE0, + 0xAC, 0xBC, 0x09, 0x46, 0xE0, 0xAC, 0xA2, 0xE0, + 0xAC, 0xBC, 0x09, 0x46, 0xE0, 0xBE, 0xB2, 0xE0, + 0xBE, 0x80, 0x9D, 0x46, 0xE0, 0xBE, 0xB3, 0xE0, + 0xBE, 0x80, 0x9D, 0x46, 0xE3, 0x83, 0x86, 0xE3, + 0x82, 0x99, 0x0D, 0x48, 0xF0, 0x9D, 0x85, 0x97, + 0xF0, 0x9D, 0x85, 0xA5, 0xAD, 0x48, 0xF0, 0x9D, + // Bytes 45c0 - 45ff + 0x85, 0x98, 0xF0, 0x9D, 0x85, 0xA5, 0xAD, 0x48, + 0xF0, 0x9D, 0x86, 0xB9, 0xF0, 0x9D, 0x85, 0xA5, + 0xAD, 0x48, 0xF0, 0x9D, 0x86, 0xBA, 0xF0, 0x9D, + 0x85, 0xA5, 0xAD, 0x49, 0xE0, 0xBE, 0xB2, 0xE0, + 0xBD, 0xB1, 0xE0, 0xBE, 0x80, 0x9E, 0x49, 0xE0, + 0xBE, 0xB3, 0xE0, 0xBD, 0xB1, 0xE0, 0xBE, 0x80, + 0x9E, 0x4C, 0xF0, 0x9D, 0x85, 0x98, 0xF0, 0x9D, + 0x85, 0xA5, 0xF0, 0x9D, 0x85, 0xAE, 0xAE, 0x4C, + // Bytes 4600 - 463f + 0xF0, 0x9D, 0x85, 0x98, 0xF0, 0x9D, 0x85, 0xA5, + 0xF0, 0x9D, 0x85, 0xAF, 0xAE, 0x4C, 0xF0, 0x9D, + 0x85, 0x98, 0xF0, 0x9D, 0x85, 0xA5, 0xF0, 0x9D, + 0x85, 0xB0, 0xAE, 0x4C, 0xF0, 0x9D, 0x85, 0x98, + 0xF0, 0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85, 0xB1, + 0xAE, 0x4C, 0xF0, 0x9D, 0x85, 0x98, 0xF0, 0x9D, + 0x85, 0xA5, 0xF0, 0x9D, 0x85, 0xB2, 0xAE, 0x4C, + 0xF0, 0x9D, 0x86, 0xB9, 0xF0, 0x9D, 0x85, 0xA5, + // Bytes 4640 - 467f + 0xF0, 0x9D, 0x85, 0xAE, 0xAE, 0x4C, 0xF0, 0x9D, + 0x86, 0xB9, 0xF0, 0x9D, 0x85, 0xA5, 0xF0, 0x9D, + 0x85, 0xAF, 0xAE, 0x4C, 0xF0, 0x9D, 0x86, 0xBA, + 0xF0, 0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85, 0xAE, + 0xAE, 0x4C, 0xF0, 0x9D, 0x86, 0xBA, 0xF0, 0x9D, + 0x85, 0xA5, 0xF0, 0x9D, 0x85, 0xAF, 0xAE, 0x83, + 0x41, 0xCC, 0x82, 0xC9, 0x83, 0x41, 0xCC, 0x86, + 0xC9, 0x83, 0x41, 0xCC, 0x87, 0xC9, 0x83, 0x41, + // Bytes 4680 - 46bf + 0xCC, 0x88, 0xC9, 0x83, 0x41, 0xCC, 0x8A, 0xC9, + 0x83, 0x41, 0xCC, 0xA3, 0xB5, 0x83, 0x43, 0xCC, + 0xA7, 0xA5, 0x83, 0x45, 0xCC, 0x82, 0xC9, 0x83, + 0x45, 0xCC, 0x84, 0xC9, 0x83, 0x45, 0xCC, 0xA3, + 0xB5, 0x83, 0x45, 0xCC, 0xA7, 0xA5, 0x83, 0x49, + 0xCC, 0x88, 0xC9, 0x83, 0x4C, 0xCC, 0xA3, 0xB5, + 0x83, 0x4F, 0xCC, 0x82, 0xC9, 0x83, 0x4F, 0xCC, + 0x83, 0xC9, 0x83, 0x4F, 0xCC, 0x84, 0xC9, 0x83, + // Bytes 46c0 - 46ff + 0x4F, 0xCC, 0x87, 0xC9, 0x83, 0x4F, 0xCC, 0x88, + 0xC9, 0x83, 0x4F, 0xCC, 0x9B, 0xAD, 0x83, 0x4F, + 0xCC, 0xA3, 0xB5, 0x83, 0x4F, 0xCC, 0xA8, 0xA5, + 0x83, 0x52, 0xCC, 0xA3, 0xB5, 0x83, 0x53, 0xCC, + 0x81, 0xC9, 0x83, 0x53, 0xCC, 0x8C, 0xC9, 0x83, + 0x53, 0xCC, 0xA3, 0xB5, 0x83, 0x55, 0xCC, 0x83, + 0xC9, 0x83, 0x55, 0xCC, 0x84, 0xC9, 0x83, 0x55, + 0xCC, 0x88, 0xC9, 0x83, 0x55, 0xCC, 0x9B, 0xAD, + // Bytes 4700 - 473f + 0x83, 0x61, 0xCC, 0x82, 0xC9, 0x83, 0x61, 0xCC, + 0x86, 0xC9, 0x83, 0x61, 0xCC, 0x87, 0xC9, 0x83, + 0x61, 0xCC, 0x88, 0xC9, 0x83, 0x61, 0xCC, 0x8A, + 0xC9, 0x83, 0x61, 0xCC, 0xA3, 0xB5, 0x83, 0x63, + 0xCC, 0xA7, 0xA5, 0x83, 0x65, 0xCC, 0x82, 0xC9, + 0x83, 0x65, 0xCC, 0x84, 0xC9, 0x83, 0x65, 0xCC, + 0xA3, 0xB5, 0x83, 0x65, 0xCC, 0xA7, 0xA5, 0x83, + 0x69, 0xCC, 0x88, 0xC9, 0x83, 0x6C, 0xCC, 0xA3, + // Bytes 4740 - 477f + 0xB5, 0x83, 0x6F, 0xCC, 0x82, 0xC9, 0x83, 0x6F, + 0xCC, 0x83, 0xC9, 0x83, 0x6F, 0xCC, 0x84, 0xC9, + 0x83, 0x6F, 0xCC, 0x87, 0xC9, 0x83, 0x6F, 0xCC, + 0x88, 0xC9, 0x83, 0x6F, 0xCC, 0x9B, 0xAD, 0x83, + 0x6F, 0xCC, 0xA3, 0xB5, 0x83, 0x6F, 0xCC, 0xA8, + 0xA5, 0x83, 0x72, 0xCC, 0xA3, 0xB5, 0x83, 0x73, + 0xCC, 0x81, 0xC9, 0x83, 0x73, 0xCC, 0x8C, 0xC9, + 0x83, 0x73, 0xCC, 0xA3, 0xB5, 0x83, 0x75, 0xCC, + // Bytes 4780 - 47bf + 0x83, 0xC9, 0x83, 0x75, 0xCC, 0x84, 0xC9, 0x83, + 0x75, 0xCC, 0x88, 0xC9, 0x83, 0x75, 0xCC, 0x9B, + 0xAD, 0x84, 0xCE, 0x91, 0xCC, 0x93, 0xC9, 0x84, + 0xCE, 0x91, 0xCC, 0x94, 0xC9, 0x84, 0xCE, 0x95, + 0xCC, 0x93, 0xC9, 0x84, 0xCE, 0x95, 0xCC, 0x94, + 0xC9, 0x84, 0xCE, 0x97, 0xCC, 0x93, 0xC9, 0x84, + 0xCE, 0x97, 0xCC, 0x94, 0xC9, 0x84, 0xCE, 0x99, + 0xCC, 0x93, 0xC9, 0x84, 0xCE, 0x99, 0xCC, 0x94, + // Bytes 47c0 - 47ff + 0xC9, 0x84, 0xCE, 0x9F, 0xCC, 0x93, 0xC9, 0x84, + 0xCE, 0x9F, 0xCC, 0x94, 0xC9, 0x84, 0xCE, 0xA5, + 0xCC, 0x94, 0xC9, 0x84, 0xCE, 0xA9, 0xCC, 0x93, + 0xC9, 0x84, 0xCE, 0xA9, 0xCC, 0x94, 0xC9, 0x84, + 0xCE, 0xB1, 0xCC, 0x80, 0xC9, 0x84, 0xCE, 0xB1, + 0xCC, 0x81, 0xC9, 0x84, 0xCE, 0xB1, 0xCC, 0x93, + 0xC9, 0x84, 0xCE, 0xB1, 0xCC, 0x94, 0xC9, 0x84, + 0xCE, 0xB1, 0xCD, 0x82, 0xC9, 0x84, 0xCE, 0xB5, + // Bytes 4800 - 483f + 0xCC, 0x93, 0xC9, 0x84, 0xCE, 0xB5, 0xCC, 0x94, + 0xC9, 0x84, 0xCE, 0xB7, 0xCC, 0x80, 0xC9, 0x84, + 0xCE, 0xB7, 0xCC, 0x81, 0xC9, 0x84, 0xCE, 0xB7, + 0xCC, 0x93, 0xC9, 0x84, 0xCE, 0xB7, 0xCC, 0x94, + 0xC9, 0x84, 0xCE, 0xB7, 0xCD, 0x82, 0xC9, 0x84, + 0xCE, 0xB9, 0xCC, 0x88, 0xC9, 0x84, 0xCE, 0xB9, + 0xCC, 0x93, 0xC9, 0x84, 0xCE, 0xB9, 0xCC, 0x94, + 0xC9, 0x84, 0xCE, 0xBF, 0xCC, 0x93, 0xC9, 0x84, + // Bytes 4840 - 487f + 0xCE, 0xBF, 0xCC, 0x94, 0xC9, 0x84, 0xCF, 0x85, + 0xCC, 0x88, 0xC9, 0x84, 0xCF, 0x85, 0xCC, 0x93, + 0xC9, 0x84, 0xCF, 0x85, 0xCC, 0x94, 0xC9, 0x84, + 0xCF, 0x89, 0xCC, 0x80, 0xC9, 0x84, 0xCF, 0x89, + 0xCC, 0x81, 0xC9, 0x84, 0xCF, 0x89, 0xCC, 0x93, + 0xC9, 0x84, 0xCF, 0x89, 0xCC, 0x94, 0xC9, 0x84, + 0xCF, 0x89, 0xCD, 0x82, 0xC9, 0x86, 0xCE, 0x91, + 0xCC, 0x93, 0xCC, 0x80, 0xCA, 0x86, 0xCE, 0x91, + // Bytes 4880 - 48bf + 0xCC, 0x93, 0xCC, 0x81, 0xCA, 0x86, 0xCE, 0x91, + 0xCC, 0x93, 0xCD, 0x82, 0xCA, 0x86, 0xCE, 0x91, + 0xCC, 0x94, 0xCC, 0x80, 0xCA, 0x86, 0xCE, 0x91, + 0xCC, 0x94, 0xCC, 0x81, 0xCA, 0x86, 0xCE, 0x91, + 0xCC, 0x94, 0xCD, 0x82, 0xCA, 0x86, 0xCE, 0x97, + 0xCC, 0x93, 0xCC, 0x80, 0xCA, 0x86, 0xCE, 0x97, + 0xCC, 0x93, 0xCC, 0x81, 0xCA, 0x86, 0xCE, 0x97, + 0xCC, 0x93, 0xCD, 0x82, 0xCA, 0x86, 0xCE, 0x97, + // Bytes 48c0 - 48ff + 0xCC, 0x94, 0xCC, 0x80, 0xCA, 0x86, 0xCE, 0x97, + 0xCC, 0x94, 0xCC, 0x81, 0xCA, 0x86, 0xCE, 0x97, + 0xCC, 0x94, 0xCD, 0x82, 0xCA, 0x86, 0xCE, 0xA9, + 0xCC, 0x93, 0xCC, 0x80, 0xCA, 0x86, 0xCE, 0xA9, + 0xCC, 0x93, 0xCC, 0x81, 0xCA, 0x86, 0xCE, 0xA9, + 0xCC, 0x93, 0xCD, 0x82, 0xCA, 0x86, 0xCE, 0xA9, + 0xCC, 0x94, 0xCC, 0x80, 0xCA, 0x86, 0xCE, 0xA9, + 0xCC, 0x94, 0xCC, 0x81, 0xCA, 0x86, 0xCE, 0xA9, + // Bytes 4900 - 493f + 0xCC, 0x94, 0xCD, 0x82, 0xCA, 0x86, 0xCE, 0xB1, + 0xCC, 0x93, 0xCC, 0x80, 0xCA, 0x86, 0xCE, 0xB1, + 0xCC, 0x93, 0xCC, 0x81, 0xCA, 0x86, 0xCE, 0xB1, + 0xCC, 0x93, 0xCD, 0x82, 0xCA, 0x86, 0xCE, 0xB1, + 0xCC, 0x94, 0xCC, 0x80, 0xCA, 0x86, 0xCE, 0xB1, + 0xCC, 0x94, 0xCC, 0x81, 0xCA, 0x86, 0xCE, 0xB1, + 0xCC, 0x94, 0xCD, 0x82, 0xCA, 0x86, 0xCE, 0xB7, + 0xCC, 0x93, 0xCC, 0x80, 0xCA, 0x86, 0xCE, 0xB7, + // Bytes 4940 - 497f + 0xCC, 0x93, 0xCC, 0x81, 0xCA, 0x86, 0xCE, 0xB7, + 0xCC, 0x93, 0xCD, 0x82, 0xCA, 0x86, 0xCE, 0xB7, + 0xCC, 0x94, 0xCC, 0x80, 0xCA, 0x86, 0xCE, 0xB7, + 0xCC, 0x94, 0xCC, 0x81, 0xCA, 0x86, 0xCE, 0xB7, + 0xCC, 0x94, 0xCD, 0x82, 0xCA, 0x86, 0xCF, 0x89, + 0xCC, 0x93, 0xCC, 0x80, 0xCA, 0x86, 0xCF, 0x89, + 0xCC, 0x93, 0xCC, 0x81, 0xCA, 0x86, 0xCF, 0x89, + 0xCC, 0x93, 0xCD, 0x82, 0xCA, 0x86, 0xCF, 0x89, + // Bytes 4980 - 49bf + 0xCC, 0x94, 0xCC, 0x80, 0xCA, 0x86, 0xCF, 0x89, + 0xCC, 0x94, 0xCC, 0x81, 0xCA, 0x86, 0xCF, 0x89, + 0xCC, 0x94, 0xCD, 0x82, 0xCA, 0x42, 0xCC, 0x80, + 0xC9, 0x32, 0x42, 0xCC, 0x81, 0xC9, 0x32, 0x42, + 0xCC, 0x93, 0xC9, 0x32, 0x44, 0xCC, 0x88, 0xCC, + 0x81, 0xCA, 0x32, 0x43, 0xE3, 0x82, 0x99, 0x0D, + 0x03, 0x43, 0xE3, 0x82, 0x9A, 0x0D, 0x03, 0x46, + 0xE0, 0xBD, 0xB1, 0xE0, 0xBD, 0xB2, 0x9E, 0x26, + // Bytes 49c0 - 49ff + 0x46, 0xE0, 0xBD, 0xB1, 0xE0, 0xBD, 0xB4, 0xA2, + 0x26, 0x46, 0xE0, 0xBD, 0xB1, 0xE0, 0xBE, 0x80, + 0x9E, 0x26, 0x00, 0x01, +} + +// nfcValues: 2944 entries, 5888 bytes +// Block 2 is the null block. +var nfcValues = [2944]uint16{ + // Block 0x0, offset 0x0 + 0x003c: 0xa000, 0x003d: 0xa000, 0x003e: 0xa000, + // Block 0x1, offset 0x40 + 0x0041: 0xa000, 0x0042: 0xa000, 0x0043: 0xa000, 0x0044: 0xa000, 0x0045: 0xa000, + 0x0046: 0xa000, 0x0047: 0xa000, 0x0048: 0xa000, 0x0049: 0xa000, 0x004a: 0xa000, 0x004b: 0xa000, + 0x004c: 0xa000, 0x004d: 0xa000, 0x004e: 0xa000, 0x004f: 0xa000, 0x0050: 0xa000, + 0x0052: 0xa000, 0x0053: 0xa000, 0x0054: 0xa000, 0x0055: 0xa000, 0x0056: 0xa000, 0x0057: 0xa000, + 0x0058: 0xa000, 0x0059: 0xa000, 0x005a: 0xa000, + 0x0061: 0xa000, 0x0062: 0xa000, 0x0063: 0xa000, + 0x0064: 0xa000, 0x0065: 0xa000, 0x0066: 0xa000, 0x0067: 0xa000, 0x0068: 0xa000, 0x0069: 0xa000, + 0x006a: 0xa000, 0x006b: 0xa000, 0x006c: 0xa000, 0x006d: 0xa000, 0x006e: 0xa000, 0x006f: 0xa000, + 0x0070: 0xa000, 0x0072: 0xa000, 0x0073: 0xa000, 0x0074: 0xa000, 0x0075: 0xa000, + 0x0076: 0xa000, 0x0077: 0xa000, 0x0078: 0xa000, 0x0079: 0xa000, 0x007a: 0xa000, + // Block 0x2, offset 0x80 + // Block 0x3, offset 0xc0 + 0x00c0: 0x2f56, 0x00c1: 0x2f5b, 0x00c2: 0x466f, 0x00c3: 0x2f60, 0x00c4: 0x467e, 0x00c5: 0x4683, + 0x00c6: 0xa000, 0x00c7: 0x468d, 0x00c8: 0x2fc9, 0x00c9: 0x2fce, 0x00ca: 0x4692, 0x00cb: 0x2fe2, + 0x00cc: 0x3055, 0x00cd: 0x305a, 0x00ce: 0x305f, 0x00cf: 0x46a6, 0x00d1: 0x30eb, + 0x00d2: 0x310e, 0x00d3: 0x3113, 0x00d4: 0x46b0, 0x00d5: 0x46b5, 0x00d6: 0x46c4, + 0x00d8: 0xa000, 0x00d9: 0x319a, 0x00da: 0x319f, 0x00db: 0x31a4, 0x00dc: 0x46f6, 0x00dd: 0x321c, + 0x00e0: 0x3262, 0x00e1: 0x3267, 0x00e2: 0x4700, 0x00e3: 0x326c, + 0x00e4: 0x470f, 0x00e5: 0x4714, 0x00e6: 0xa000, 0x00e7: 0x471e, 0x00e8: 0x32d5, 0x00e9: 0x32da, + 0x00ea: 0x4723, 0x00eb: 0x32ee, 0x00ec: 0x3366, 0x00ed: 0x336b, 0x00ee: 0x3370, 0x00ef: 0x4737, + 0x00f1: 0x33fc, 0x00f2: 0x341f, 0x00f3: 0x3424, 0x00f4: 0x4741, 0x00f5: 0x4746, + 0x00f6: 0x4755, 0x00f8: 0xa000, 0x00f9: 0x34b0, 0x00fa: 0x34b5, 0x00fb: 0x34ba, + 0x00fc: 0x4787, 0x00fd: 0x3537, 0x00ff: 0x3550, + // Block 0x4, offset 0x100 + 0x0100: 0x2f65, 0x0101: 0x3271, 0x0102: 0x4674, 0x0103: 0x4705, 0x0104: 0x2f83, 0x0105: 0x328f, + 0x0106: 0x2f97, 0x0107: 0x32a3, 0x0108: 0x2f9c, 0x0109: 0x32a8, 0x010a: 0x2fa1, 0x010b: 0x32ad, + 0x010c: 0x2fa6, 0x010d: 0x32b2, 0x010e: 0x2fb0, 0x010f: 0x32bc, + 0x0112: 0x4697, 0x0113: 0x4728, 0x0114: 0x2fd8, 0x0115: 0x32e4, 0x0116: 0x2fdd, 0x0117: 0x32e9, + 0x0118: 0x2ffb, 0x0119: 0x3307, 0x011a: 0x2fec, 0x011b: 0x32f8, 0x011c: 0x3014, 0x011d: 0x3320, + 0x011e: 0x301e, 0x011f: 0x332a, 0x0120: 0x3023, 0x0121: 0x332f, 0x0122: 0x302d, 0x0123: 0x3339, + 0x0124: 0x3032, 0x0125: 0x333e, 0x0128: 0x3064, 0x0129: 0x3375, + 0x012a: 0x3069, 0x012b: 0x337a, 0x012c: 0x306e, 0x012d: 0x337f, 0x012e: 0x3091, 0x012f: 0x339d, + 0x0130: 0x3073, 0x0134: 0x309b, 0x0135: 0x33a7, + 0x0136: 0x30af, 0x0137: 0x33c0, 0x0139: 0x30b9, 0x013a: 0x33ca, 0x013b: 0x30c3, + 0x013c: 0x33d4, 0x013d: 0x30be, 0x013e: 0x33cf, + // Block 0x5, offset 0x140 + 0x0143: 0x30e6, 0x0144: 0x33f7, 0x0145: 0x30ff, + 0x0146: 0x3410, 0x0147: 0x30f5, 0x0148: 0x3406, + 0x014c: 0x46ba, 0x014d: 0x474b, 0x014e: 0x3118, 0x014f: 0x3429, 0x0150: 0x3122, 0x0151: 0x3433, + 0x0154: 0x3140, 0x0155: 0x3451, 0x0156: 0x3159, 0x0157: 0x346a, + 0x0158: 0x314a, 0x0159: 0x345b, 0x015a: 0x46dd, 0x015b: 0x476e, 0x015c: 0x3163, 0x015d: 0x3474, + 0x015e: 0x3172, 0x015f: 0x3483, 0x0160: 0x46e2, 0x0161: 0x4773, 0x0162: 0x318b, 0x0163: 0x34a1, + 0x0164: 0x317c, 0x0165: 0x3492, 0x0168: 0x46ec, 0x0169: 0x477d, + 0x016a: 0x46f1, 0x016b: 0x4782, 0x016c: 0x31a9, 0x016d: 0x34bf, 0x016e: 0x31b3, 0x016f: 0x34c9, + 0x0170: 0x31b8, 0x0171: 0x34ce, 0x0172: 0x31d6, 0x0173: 0x34ec, 0x0174: 0x31f9, 0x0175: 0x350f, + 0x0176: 0x3221, 0x0177: 0x353c, 0x0178: 0x3235, 0x0179: 0x3244, 0x017a: 0x3564, 0x017b: 0x324e, + 0x017c: 0x356e, 0x017d: 0x3253, 0x017e: 0x3573, 0x017f: 0xa000, + // Block 0x6, offset 0x180 + 0x0184: 0x8100, 0x0185: 0x8100, + 0x0186: 0x8100, + 0x018d: 0x2f6f, 0x018e: 0x327b, 0x018f: 0x307d, 0x0190: 0x3389, 0x0191: 0x3127, + 0x0192: 0x3438, 0x0193: 0x31bd, 0x0194: 0x34d3, 0x0195: 0x39b6, 0x0196: 0x3b45, 0x0197: 0x39af, + 0x0198: 0x3b3e, 0x0199: 0x39bd, 0x019a: 0x3b4c, 0x019b: 0x39a8, 0x019c: 0x3b37, + 0x019e: 0x3897, 0x019f: 0x3a26, 0x01a0: 0x3890, 0x01a1: 0x3a1f, 0x01a2: 0x359a, 0x01a3: 0x35ac, + 0x01a6: 0x3028, 0x01a7: 0x3334, 0x01a8: 0x30a5, 0x01a9: 0x33b6, + 0x01aa: 0x46d3, 0x01ab: 0x4764, 0x01ac: 0x3977, 0x01ad: 0x3b06, 0x01ae: 0x35be, 0x01af: 0x35c4, + 0x01b0: 0x33ac, 0x01b4: 0x300f, 0x01b5: 0x331b, + 0x01b8: 0x30e1, 0x01b9: 0x33f2, 0x01ba: 0x389e, 0x01bb: 0x3a2d, + 0x01bc: 0x3594, 0x01bd: 0x35a6, 0x01be: 0x35a0, 0x01bf: 0x35b2, + // Block 0x7, offset 0x1c0 + 0x01c0: 0x2f74, 0x01c1: 0x3280, 0x01c2: 0x2f79, 0x01c3: 0x3285, 0x01c4: 0x2ff1, 0x01c5: 0x32fd, + 0x01c6: 0x2ff6, 0x01c7: 0x3302, 0x01c8: 0x3082, 0x01c9: 0x338e, 0x01ca: 0x3087, 0x01cb: 0x3393, + 0x01cc: 0x312c, 0x01cd: 0x343d, 0x01ce: 0x3131, 0x01cf: 0x3442, 0x01d0: 0x314f, 0x01d1: 0x3460, + 0x01d2: 0x3154, 0x01d3: 0x3465, 0x01d4: 0x31c2, 0x01d5: 0x34d8, 0x01d6: 0x31c7, 0x01d7: 0x34dd, + 0x01d8: 0x316d, 0x01d9: 0x347e, 0x01da: 0x3186, 0x01db: 0x349c, + 0x01de: 0x3041, 0x01df: 0x334d, + 0x01e6: 0x4679, 0x01e7: 0x470a, 0x01e8: 0x46a1, 0x01e9: 0x4732, + 0x01ea: 0x3946, 0x01eb: 0x3ad5, 0x01ec: 0x3923, 0x01ed: 0x3ab2, 0x01ee: 0x46bf, 0x01ef: 0x4750, + 0x01f0: 0x393f, 0x01f1: 0x3ace, 0x01f2: 0x322b, 0x01f3: 0x3546, + // Block 0x8, offset 0x200 + 0x0200: 0x9932, 0x0201: 0x9932, 0x0202: 0x9932, 0x0203: 0x9932, 0x0204: 0x9932, 0x0205: 0x8132, + 0x0206: 0x9932, 0x0207: 0x9932, 0x0208: 0x9932, 0x0209: 0x9932, 0x020a: 0x9932, 0x020b: 0x9932, + 0x020c: 0x9932, 0x020d: 0x8132, 0x020e: 0x8132, 0x020f: 0x9932, 0x0210: 0x8132, 0x0211: 0x9932, + 0x0212: 0x8132, 0x0213: 0x9932, 0x0214: 0x9932, 0x0215: 0x8133, 0x0216: 0x812d, 0x0217: 0x812d, + 0x0218: 0x812d, 0x0219: 0x812d, 0x021a: 0x8133, 0x021b: 0x992b, 0x021c: 0x812d, 0x021d: 0x812d, + 0x021e: 0x812d, 0x021f: 0x812d, 0x0220: 0x812d, 0x0221: 0x8129, 0x0222: 0x8129, 0x0223: 0x992d, + 0x0224: 0x992d, 0x0225: 0x992d, 0x0226: 0x992d, 0x0227: 0x9929, 0x0228: 0x9929, 0x0229: 0x812d, + 0x022a: 0x812d, 0x022b: 0x812d, 0x022c: 0x812d, 0x022d: 0x992d, 0x022e: 0x992d, 0x022f: 0x812d, + 0x0230: 0x992d, 0x0231: 0x992d, 0x0232: 0x812d, 0x0233: 0x812d, 0x0234: 0x8101, 0x0235: 0x8101, + 0x0236: 0x8101, 0x0237: 0x8101, 0x0238: 0x9901, 0x0239: 0x812d, 0x023a: 0x812d, 0x023b: 0x812d, + 0x023c: 0x812d, 0x023d: 0x8132, 0x023e: 0x8132, 0x023f: 0x8132, + // Block 0x9, offset 0x240 + 0x0240: 0x4995, 0x0241: 0x499a, 0x0242: 0x9932, 0x0243: 0x499f, 0x0244: 0x49a4, 0x0245: 0x9936, + 0x0246: 0x8132, 0x0247: 0x812d, 0x0248: 0x812d, 0x0249: 0x812d, 0x024a: 0x8132, 0x024b: 0x8132, + 0x024c: 0x8132, 0x024d: 0x812d, 0x024e: 0x812d, 0x0250: 0x8132, 0x0251: 0x8132, + 0x0252: 0x8132, 0x0253: 0x812d, 0x0254: 0x812d, 0x0255: 0x812d, 0x0256: 0x812d, 0x0257: 0x8132, + 0x0258: 0x8133, 0x0259: 0x812d, 0x025a: 0x812d, 0x025b: 0x8132, 0x025c: 0x8134, 0x025d: 0x8135, + 0x025e: 0x8135, 0x025f: 0x8134, 0x0260: 0x8135, 0x0261: 0x8135, 0x0262: 0x8134, 0x0263: 0x8132, + 0x0264: 0x8132, 0x0265: 0x8132, 0x0266: 0x8132, 0x0267: 0x8132, 0x0268: 0x8132, 0x0269: 0x8132, + 0x026a: 0x8132, 0x026b: 0x8132, 0x026c: 0x8132, 0x026d: 0x8132, 0x026e: 0x8132, 0x026f: 0x8132, + 0x0274: 0x016d, + 0x027a: 0x8100, + 0x027e: 0x0037, + // Block 0xa, offset 0x280 + 0x0284: 0x8100, 0x0285: 0x3588, + 0x0286: 0x35d0, 0x0287: 0x00ce, 0x0288: 0x35ee, 0x0289: 0x35fa, 0x028a: 0x360c, + 0x028c: 0x362a, 0x028e: 0x363c, 0x028f: 0x365a, 0x0290: 0x3def, 0x0291: 0xa000, + 0x0295: 0xa000, 0x0297: 0xa000, + 0x0299: 0xa000, + 0x029f: 0xa000, 0x02a1: 0xa000, + 0x02a5: 0xa000, 0x02a9: 0xa000, + 0x02aa: 0x361e, 0x02ab: 0x364e, 0x02ac: 0x47e5, 0x02ad: 0x367e, 0x02ae: 0x480f, 0x02af: 0x3690, + 0x02b0: 0x3e57, 0x02b1: 0xa000, 0x02b5: 0xa000, + 0x02b7: 0xa000, 0x02b9: 0xa000, + 0x02bf: 0xa000, + // Block 0xb, offset 0x2c0 + 0x02c0: 0x3708, 0x02c1: 0x3714, 0x02c3: 0x3702, + 0x02c6: 0xa000, 0x02c7: 0x36f0, + 0x02cc: 0x3744, 0x02cd: 0x372c, 0x02ce: 0x3756, 0x02d0: 0xa000, + 0x02d3: 0xa000, 0x02d5: 0xa000, 0x02d6: 0xa000, 0x02d7: 0xa000, + 0x02d8: 0xa000, 0x02d9: 0x3738, 0x02da: 0xa000, + 0x02de: 0xa000, 0x02e3: 0xa000, + 0x02e7: 0xa000, + 0x02eb: 0xa000, 0x02ed: 0xa000, + 0x02f0: 0xa000, 0x02f3: 0xa000, 0x02f5: 0xa000, + 0x02f6: 0xa000, 0x02f7: 0xa000, 0x02f8: 0xa000, 0x02f9: 0x37bc, 0x02fa: 0xa000, + 0x02fe: 0xa000, + // Block 0xc, offset 0x300 + 0x0301: 0x371a, 0x0302: 0x379e, + 0x0310: 0x36f6, 0x0311: 0x377a, + 0x0312: 0x36fc, 0x0313: 0x3780, 0x0316: 0x370e, 0x0317: 0x3792, + 0x0318: 0xa000, 0x0319: 0xa000, 0x031a: 0x3810, 0x031b: 0x3816, 0x031c: 0x3720, 0x031d: 0x37a4, + 0x031e: 0x3726, 0x031f: 0x37aa, 0x0322: 0x3732, 0x0323: 0x37b6, + 0x0324: 0x373e, 0x0325: 0x37c2, 0x0326: 0x374a, 0x0327: 0x37ce, 0x0328: 0xa000, 0x0329: 0xa000, + 0x032a: 0x381c, 0x032b: 0x3822, 0x032c: 0x3774, 0x032d: 0x37f8, 0x032e: 0x3750, 0x032f: 0x37d4, + 0x0330: 0x375c, 0x0331: 0x37e0, 0x0332: 0x3762, 0x0333: 0x37e6, 0x0334: 0x3768, 0x0335: 0x37ec, + 0x0338: 0x376e, 0x0339: 0x37f2, + // Block 0xd, offset 0x340 + 0x0351: 0x812d, + 0x0352: 0x8132, 0x0353: 0x8132, 0x0354: 0x8132, 0x0355: 0x8132, 0x0356: 0x812d, 0x0357: 0x8132, + 0x0358: 0x8132, 0x0359: 0x8132, 0x035a: 0x812e, 0x035b: 0x812d, 0x035c: 0x8132, 0x035d: 0x8132, + 0x035e: 0x8132, 0x035f: 0x8132, 0x0360: 0x8132, 0x0361: 0x8132, 0x0362: 0x812d, 0x0363: 0x812d, + 0x0364: 0x812d, 0x0365: 0x812d, 0x0366: 0x812d, 0x0367: 0x812d, 0x0368: 0x8132, 0x0369: 0x8132, + 0x036a: 0x812d, 0x036b: 0x8132, 0x036c: 0x8132, 0x036d: 0x812e, 0x036e: 0x8131, 0x036f: 0x8132, + 0x0370: 0x8105, 0x0371: 0x8106, 0x0372: 0x8107, 0x0373: 0x8108, 0x0374: 0x8109, 0x0375: 0x810a, + 0x0376: 0x810b, 0x0377: 0x810c, 0x0378: 0x810d, 0x0379: 0x810e, 0x037a: 0x810e, 0x037b: 0x810f, + 0x037c: 0x8110, 0x037d: 0x8111, 0x037f: 0x8112, + // Block 0xe, offset 0x380 + 0x0388: 0xa000, 0x038a: 0xa000, 0x038b: 0x8116, + 0x038c: 0x8117, 0x038d: 0x8118, 0x038e: 0x8119, 0x038f: 0x811a, 0x0390: 0x811b, 0x0391: 0x811c, + 0x0392: 0x811d, 0x0393: 0x9932, 0x0394: 0x9932, 0x0395: 0x992d, 0x0396: 0x812d, 0x0397: 0x8132, + 0x0398: 0x8132, 0x0399: 0x8132, 0x039a: 0x8132, 0x039b: 0x8132, 0x039c: 0x812d, 0x039d: 0x8132, + 0x039e: 0x8132, 0x039f: 0x812d, + 0x03b0: 0x811e, + // Block 0xf, offset 0x3c0 + 0x03c5: 0xa000, + 0x03c6: 0x1943, 0x03c7: 0xa000, 0x03c8: 0x194a, 0x03c9: 0xa000, 0x03ca: 0x1951, 0x03cb: 0xa000, + 0x03cc: 0x1958, 0x03cd: 0xa000, 0x03ce: 0x195f, 0x03d1: 0xa000, + 0x03d2: 0x1966, + 0x03f4: 0x8102, 0x03f5: 0x9900, + 0x03fa: 0xa000, 0x03fb: 0x196d, + 0x03fc: 0xa000, 0x03fd: 0x1974, 0x03fe: 0xa000, 0x03ff: 0xa000, + // Block 0x10, offset 0x400 + 0x0400: 0x2f7e, 0x0401: 0x328a, 0x0402: 0x2f88, 0x0403: 0x3294, 0x0404: 0x2f8d, 0x0405: 0x3299, + 0x0406: 0x2f92, 0x0407: 0x329e, 0x0408: 0x38b3, 0x0409: 0x3a42, 0x040a: 0x2fab, 0x040b: 0x32b7, + 0x040c: 0x2fb5, 0x040d: 0x32c1, 0x040e: 0x2fc4, 0x040f: 0x32d0, 0x0410: 0x2fba, 0x0411: 0x32c6, + 0x0412: 0x2fbf, 0x0413: 0x32cb, 0x0414: 0x38d6, 0x0415: 0x3a65, 0x0416: 0x38dd, 0x0417: 0x3a6c, + 0x0418: 0x3000, 0x0419: 0x330c, 0x041a: 0x3005, 0x041b: 0x3311, 0x041c: 0x38eb, 0x041d: 0x3a7a, + 0x041e: 0x300a, 0x041f: 0x3316, 0x0420: 0x3019, 0x0421: 0x3325, 0x0422: 0x3037, 0x0423: 0x3343, + 0x0424: 0x3046, 0x0425: 0x3352, 0x0426: 0x303c, 0x0427: 0x3348, 0x0428: 0x304b, 0x0429: 0x3357, + 0x042a: 0x3050, 0x042b: 0x335c, 0x042c: 0x3096, 0x042d: 0x33a2, 0x042e: 0x38f2, 0x042f: 0x3a81, + 0x0430: 0x30a0, 0x0431: 0x33b1, 0x0432: 0x30aa, 0x0433: 0x33bb, 0x0434: 0x30b4, 0x0435: 0x33c5, + 0x0436: 0x46ab, 0x0437: 0x473c, 0x0438: 0x38f9, 0x0439: 0x3a88, 0x043a: 0x30cd, 0x043b: 0x33de, + 0x043c: 0x30c8, 0x043d: 0x33d9, 0x043e: 0x30d2, 0x043f: 0x33e3, + // Block 0x11, offset 0x440 + 0x0440: 0x30d7, 0x0441: 0x33e8, 0x0442: 0x30dc, 0x0443: 0x33ed, 0x0444: 0x30f0, 0x0445: 0x3401, + 0x0446: 0x30fa, 0x0447: 0x340b, 0x0448: 0x3109, 0x0449: 0x341a, 0x044a: 0x3104, 0x044b: 0x3415, + 0x044c: 0x391c, 0x044d: 0x3aab, 0x044e: 0x392a, 0x044f: 0x3ab9, 0x0450: 0x3931, 0x0451: 0x3ac0, + 0x0452: 0x3938, 0x0453: 0x3ac7, 0x0454: 0x3136, 0x0455: 0x3447, 0x0456: 0x313b, 0x0457: 0x344c, + 0x0458: 0x3145, 0x0459: 0x3456, 0x045a: 0x46d8, 0x045b: 0x4769, 0x045c: 0x397e, 0x045d: 0x3b0d, + 0x045e: 0x315e, 0x045f: 0x346f, 0x0460: 0x3168, 0x0461: 0x3479, 0x0462: 0x46e7, 0x0463: 0x4778, + 0x0464: 0x3985, 0x0465: 0x3b14, 0x0466: 0x398c, 0x0467: 0x3b1b, 0x0468: 0x3993, 0x0469: 0x3b22, + 0x046a: 0x3177, 0x046b: 0x3488, 0x046c: 0x3181, 0x046d: 0x3497, 0x046e: 0x3195, 0x046f: 0x34ab, + 0x0470: 0x3190, 0x0471: 0x34a6, 0x0472: 0x31d1, 0x0473: 0x34e7, 0x0474: 0x31e0, 0x0475: 0x34f6, + 0x0476: 0x31db, 0x0477: 0x34f1, 0x0478: 0x399a, 0x0479: 0x3b29, 0x047a: 0x39a1, 0x047b: 0x3b30, + 0x047c: 0x31e5, 0x047d: 0x34fb, 0x047e: 0x31ea, 0x047f: 0x3500, + // Block 0x12, offset 0x480 + 0x0480: 0x31ef, 0x0481: 0x3505, 0x0482: 0x31f4, 0x0483: 0x350a, 0x0484: 0x3203, 0x0485: 0x3519, + 0x0486: 0x31fe, 0x0487: 0x3514, 0x0488: 0x3208, 0x0489: 0x3523, 0x048a: 0x320d, 0x048b: 0x3528, + 0x048c: 0x3212, 0x048d: 0x352d, 0x048e: 0x3230, 0x048f: 0x354b, 0x0490: 0x3249, 0x0491: 0x3569, + 0x0492: 0x3258, 0x0493: 0x3578, 0x0494: 0x325d, 0x0495: 0x357d, 0x0496: 0x3361, 0x0497: 0x348d, + 0x0498: 0x351e, 0x0499: 0x355a, 0x049b: 0x35b8, + 0x04a0: 0x4688, 0x04a1: 0x4719, 0x04a2: 0x2f6a, 0x04a3: 0x3276, + 0x04a4: 0x385f, 0x04a5: 0x39ee, 0x04a6: 0x3858, 0x04a7: 0x39e7, 0x04a8: 0x386d, 0x04a9: 0x39fc, + 0x04aa: 0x3866, 0x04ab: 0x39f5, 0x04ac: 0x38a5, 0x04ad: 0x3a34, 0x04ae: 0x387b, 0x04af: 0x3a0a, + 0x04b0: 0x3874, 0x04b1: 0x3a03, 0x04b2: 0x3889, 0x04b3: 0x3a18, 0x04b4: 0x3882, 0x04b5: 0x3a11, + 0x04b6: 0x38ac, 0x04b7: 0x3a3b, 0x04b8: 0x469c, 0x04b9: 0x472d, 0x04ba: 0x2fe7, 0x04bb: 0x32f3, + 0x04bc: 0x2fd3, 0x04bd: 0x32df, 0x04be: 0x38c1, 0x04bf: 0x3a50, + // Block 0x13, offset 0x4c0 + 0x04c0: 0x38ba, 0x04c1: 0x3a49, 0x04c2: 0x38cf, 0x04c3: 0x3a5e, 0x04c4: 0x38c8, 0x04c5: 0x3a57, + 0x04c6: 0x38e4, 0x04c7: 0x3a73, 0x04c8: 0x3078, 0x04c9: 0x3384, 0x04ca: 0x308c, 0x04cb: 0x3398, + 0x04cc: 0x46ce, 0x04cd: 0x475f, 0x04ce: 0x311d, 0x04cf: 0x342e, 0x04d0: 0x3907, 0x04d1: 0x3a96, + 0x04d2: 0x3900, 0x04d3: 0x3a8f, 0x04d4: 0x3915, 0x04d5: 0x3aa4, 0x04d6: 0x390e, 0x04d7: 0x3a9d, + 0x04d8: 0x3970, 0x04d9: 0x3aff, 0x04da: 0x3954, 0x04db: 0x3ae3, 0x04dc: 0x394d, 0x04dd: 0x3adc, + 0x04de: 0x3962, 0x04df: 0x3af1, 0x04e0: 0x395b, 0x04e1: 0x3aea, 0x04e2: 0x3969, 0x04e3: 0x3af8, + 0x04e4: 0x31cc, 0x04e5: 0x34e2, 0x04e6: 0x31ae, 0x04e7: 0x34c4, 0x04e8: 0x39cb, 0x04e9: 0x3b5a, + 0x04ea: 0x39c4, 0x04eb: 0x3b53, 0x04ec: 0x39d9, 0x04ed: 0x3b68, 0x04ee: 0x39d2, 0x04ef: 0x3b61, + 0x04f0: 0x39e0, 0x04f1: 0x3b6f, 0x04f2: 0x3217, 0x04f3: 0x3532, 0x04f4: 0x323f, 0x04f5: 0x355f, + 0x04f6: 0x323a, 0x04f7: 0x3555, 0x04f8: 0x3226, 0x04f9: 0x3541, + // Block 0x14, offset 0x500 + 0x0500: 0x47eb, 0x0501: 0x47f1, 0x0502: 0x4905, 0x0503: 0x491d, 0x0504: 0x490d, 0x0505: 0x4925, + 0x0506: 0x4915, 0x0507: 0x492d, 0x0508: 0x4791, 0x0509: 0x4797, 0x050a: 0x4875, 0x050b: 0x488d, + 0x050c: 0x487d, 0x050d: 0x4895, 0x050e: 0x4885, 0x050f: 0x489d, 0x0510: 0x47fd, 0x0511: 0x4803, + 0x0512: 0x3d9f, 0x0513: 0x3daf, 0x0514: 0x3da7, 0x0515: 0x3db7, + 0x0518: 0x479d, 0x0519: 0x47a3, 0x051a: 0x3ccf, 0x051b: 0x3cdf, 0x051c: 0x3cd7, 0x051d: 0x3ce7, + 0x0520: 0x4815, 0x0521: 0x481b, 0x0522: 0x4935, 0x0523: 0x494d, + 0x0524: 0x493d, 0x0525: 0x4955, 0x0526: 0x4945, 0x0527: 0x495d, 0x0528: 0x47a9, 0x0529: 0x47af, + 0x052a: 0x48a5, 0x052b: 0x48bd, 0x052c: 0x48ad, 0x052d: 0x48c5, 0x052e: 0x48b5, 0x052f: 0x48cd, + 0x0530: 0x482d, 0x0531: 0x4833, 0x0532: 0x3dff, 0x0533: 0x3e17, 0x0534: 0x3e07, 0x0535: 0x3e1f, + 0x0536: 0x3e0f, 0x0537: 0x3e27, 0x0538: 0x47b5, 0x0539: 0x47bb, 0x053a: 0x3cff, 0x053b: 0x3d17, + 0x053c: 0x3d07, 0x053d: 0x3d1f, 0x053e: 0x3d0f, 0x053f: 0x3d27, + // Block 0x15, offset 0x540 + 0x0540: 0x4839, 0x0541: 0x483f, 0x0542: 0x3e2f, 0x0543: 0x3e3f, 0x0544: 0x3e37, 0x0545: 0x3e47, + 0x0548: 0x47c1, 0x0549: 0x47c7, 0x054a: 0x3d2f, 0x054b: 0x3d3f, + 0x054c: 0x3d37, 0x054d: 0x3d47, 0x0550: 0x484b, 0x0551: 0x4851, + 0x0552: 0x3e67, 0x0553: 0x3e7f, 0x0554: 0x3e6f, 0x0555: 0x3e87, 0x0556: 0x3e77, 0x0557: 0x3e8f, + 0x0559: 0x47cd, 0x055b: 0x3d4f, 0x055d: 0x3d57, + 0x055f: 0x3d5f, 0x0560: 0x4863, 0x0561: 0x4869, 0x0562: 0x4965, 0x0563: 0x497d, + 0x0564: 0x496d, 0x0565: 0x4985, 0x0566: 0x4975, 0x0567: 0x498d, 0x0568: 0x47d3, 0x0569: 0x47d9, + 0x056a: 0x48d5, 0x056b: 0x48ed, 0x056c: 0x48dd, 0x056d: 0x48f5, 0x056e: 0x48e5, 0x056f: 0x48fd, + 0x0570: 0x47df, 0x0571: 0x4305, 0x0572: 0x3678, 0x0573: 0x430b, 0x0574: 0x4809, 0x0575: 0x4311, + 0x0576: 0x368a, 0x0577: 0x4317, 0x0578: 0x36a8, 0x0579: 0x431d, 0x057a: 0x36c0, 0x057b: 0x4323, + 0x057c: 0x4857, 0x057d: 0x4329, + // Block 0x16, offset 0x580 + 0x0580: 0x3d87, 0x0581: 0x3d8f, 0x0582: 0x416b, 0x0583: 0x4189, 0x0584: 0x4175, 0x0585: 0x4193, + 0x0586: 0x417f, 0x0587: 0x419d, 0x0588: 0x3cbf, 0x0589: 0x3cc7, 0x058a: 0x40b7, 0x058b: 0x40d5, + 0x058c: 0x40c1, 0x058d: 0x40df, 0x058e: 0x40cb, 0x058f: 0x40e9, 0x0590: 0x3dcf, 0x0591: 0x3dd7, + 0x0592: 0x41a7, 0x0593: 0x41c5, 0x0594: 0x41b1, 0x0595: 0x41cf, 0x0596: 0x41bb, 0x0597: 0x41d9, + 0x0598: 0x3cef, 0x0599: 0x3cf7, 0x059a: 0x40f3, 0x059b: 0x4111, 0x059c: 0x40fd, 0x059d: 0x411b, + 0x059e: 0x4107, 0x059f: 0x4125, 0x05a0: 0x3ea7, 0x05a1: 0x3eaf, 0x05a2: 0x41e3, 0x05a3: 0x4201, + 0x05a4: 0x41ed, 0x05a5: 0x420b, 0x05a6: 0x41f7, 0x05a7: 0x4215, 0x05a8: 0x3d67, 0x05a9: 0x3d6f, + 0x05aa: 0x412f, 0x05ab: 0x414d, 0x05ac: 0x4139, 0x05ad: 0x4157, 0x05ae: 0x4143, 0x05af: 0x4161, + 0x05b0: 0x366c, 0x05b1: 0x3666, 0x05b2: 0x3d77, 0x05b3: 0x3672, 0x05b4: 0x3d7f, + 0x05b6: 0x47f7, 0x05b7: 0x3d97, 0x05b8: 0x35dc, 0x05b9: 0x35d6, 0x05ba: 0x35ca, 0x05bb: 0x42d5, + 0x05bc: 0x35e2, 0x05bd: 0x8100, 0x05be: 0x01d0, 0x05bf: 0xa100, + // Block 0x17, offset 0x5c0 + 0x05c0: 0x8100, 0x05c1: 0x358e, 0x05c2: 0x3dbf, 0x05c3: 0x3684, 0x05c4: 0x3dc7, + 0x05c6: 0x4821, 0x05c7: 0x3ddf, 0x05c8: 0x35e8, 0x05c9: 0x42db, 0x05ca: 0x35f4, 0x05cb: 0x42e1, + 0x05cc: 0x3600, 0x05cd: 0x3b76, 0x05ce: 0x3b7d, 0x05cf: 0x3b84, 0x05d0: 0x369c, 0x05d1: 0x3696, + 0x05d2: 0x3de7, 0x05d3: 0x44cb, 0x05d6: 0x36a2, 0x05d7: 0x3df7, + 0x05d8: 0x3618, 0x05d9: 0x3612, 0x05da: 0x3606, 0x05db: 0x42e7, 0x05dd: 0x3b8b, + 0x05de: 0x3b92, 0x05df: 0x3b99, 0x05e0: 0x36d2, 0x05e1: 0x36cc, 0x05e2: 0x3e4f, 0x05e3: 0x44d3, + 0x05e4: 0x36b4, 0x05e5: 0x36ba, 0x05e6: 0x36d8, 0x05e7: 0x3e5f, 0x05e8: 0x3648, 0x05e9: 0x3642, + 0x05ea: 0x3636, 0x05eb: 0x42f3, 0x05ec: 0x3630, 0x05ed: 0x3582, 0x05ee: 0x42cf, 0x05ef: 0x0081, + 0x05f2: 0x3e97, 0x05f3: 0x36de, 0x05f4: 0x3e9f, + 0x05f6: 0x486f, 0x05f7: 0x3eb7, 0x05f8: 0x3624, 0x05f9: 0x42ed, 0x05fa: 0x3654, 0x05fb: 0x42ff, + 0x05fc: 0x3660, 0x05fd: 0x423d, 0x05fe: 0xa100, + // Block 0x18, offset 0x600 + 0x0601: 0x3bed, 0x0603: 0xa000, 0x0604: 0x3bf4, 0x0605: 0xa000, + 0x0607: 0x3bfb, 0x0608: 0xa000, 0x0609: 0x3c02, + 0x060d: 0xa000, + 0x0620: 0x2f4c, 0x0621: 0xa000, 0x0622: 0x3c10, + 0x0624: 0xa000, 0x0625: 0xa000, + 0x062d: 0x3c09, 0x062e: 0x2f47, 0x062f: 0x2f51, + 0x0630: 0x3c17, 0x0631: 0x3c1e, 0x0632: 0xa000, 0x0633: 0xa000, 0x0634: 0x3c25, 0x0635: 0x3c2c, + 0x0636: 0xa000, 0x0637: 0xa000, 0x0638: 0x3c33, 0x0639: 0x3c3a, 0x063a: 0xa000, 0x063b: 0xa000, + 0x063c: 0xa000, 0x063d: 0xa000, + // Block 0x19, offset 0x640 + 0x0640: 0x3c41, 0x0641: 0x3c48, 0x0642: 0xa000, 0x0643: 0xa000, 0x0644: 0x3c5d, 0x0645: 0x3c64, + 0x0646: 0xa000, 0x0647: 0xa000, 0x0648: 0x3c6b, 0x0649: 0x3c72, + 0x0651: 0xa000, + 0x0652: 0xa000, + 0x0662: 0xa000, + 0x0668: 0xa000, 0x0669: 0xa000, + 0x066b: 0xa000, 0x066c: 0x3c87, 0x066d: 0x3c8e, 0x066e: 0x3c95, 0x066f: 0x3c9c, + 0x0672: 0xa000, 0x0673: 0xa000, 0x0674: 0xa000, 0x0675: 0xa000, + // Block 0x1a, offset 0x680 + 0x0686: 0xa000, 0x068b: 0xa000, + 0x068c: 0x3eef, 0x068d: 0xa000, 0x068e: 0x3ef7, 0x068f: 0xa000, 0x0690: 0x3eff, 0x0691: 0xa000, + 0x0692: 0x3f07, 0x0693: 0xa000, 0x0694: 0x3f0f, 0x0695: 0xa000, 0x0696: 0x3f17, 0x0697: 0xa000, + 0x0698: 0x3f1f, 0x0699: 0xa000, 0x069a: 0x3f27, 0x069b: 0xa000, 0x069c: 0x3f2f, 0x069d: 0xa000, + 0x069e: 0x3f37, 0x069f: 0xa000, 0x06a0: 0x3f3f, 0x06a1: 0xa000, 0x06a2: 0x3f47, + 0x06a4: 0xa000, 0x06a5: 0x3f4f, 0x06a6: 0xa000, 0x06a7: 0x3f57, 0x06a8: 0xa000, 0x06a9: 0x3f5f, + 0x06af: 0xa000, + 0x06b0: 0x3f67, 0x06b1: 0x3f6f, 0x06b2: 0xa000, 0x06b3: 0x3f77, 0x06b4: 0x3f7f, 0x06b5: 0xa000, + 0x06b6: 0x3f87, 0x06b7: 0x3f8f, 0x06b8: 0xa000, 0x06b9: 0x3f97, 0x06ba: 0x3f9f, 0x06bb: 0xa000, + 0x06bc: 0x3fa7, 0x06bd: 0x3faf, + // Block 0x1b, offset 0x6c0 + 0x06d4: 0x3ee7, + 0x06d9: 0x9903, 0x06da: 0x9903, 0x06db: 0x8100, 0x06dc: 0x8100, 0x06dd: 0xa000, + 0x06de: 0x3fb7, + 0x06e6: 0xa000, + 0x06eb: 0xa000, 0x06ec: 0x3fc7, 0x06ed: 0xa000, 0x06ee: 0x3fcf, 0x06ef: 0xa000, + 0x06f0: 0x3fd7, 0x06f1: 0xa000, 0x06f2: 0x3fdf, 0x06f3: 0xa000, 0x06f4: 0x3fe7, 0x06f5: 0xa000, + 0x06f6: 0x3fef, 0x06f7: 0xa000, 0x06f8: 0x3ff7, 0x06f9: 0xa000, 0x06fa: 0x3fff, 0x06fb: 0xa000, + 0x06fc: 0x4007, 0x06fd: 0xa000, 0x06fe: 0x400f, 0x06ff: 0xa000, + // Block 0x1c, offset 0x700 + 0x0700: 0x4017, 0x0701: 0xa000, 0x0702: 0x401f, 0x0704: 0xa000, 0x0705: 0x4027, + 0x0706: 0xa000, 0x0707: 0x402f, 0x0708: 0xa000, 0x0709: 0x4037, + 0x070f: 0xa000, 0x0710: 0x403f, 0x0711: 0x4047, + 0x0712: 0xa000, 0x0713: 0x404f, 0x0714: 0x4057, 0x0715: 0xa000, 0x0716: 0x405f, 0x0717: 0x4067, + 0x0718: 0xa000, 0x0719: 0x406f, 0x071a: 0x4077, 0x071b: 0xa000, 0x071c: 0x407f, 0x071d: 0x4087, + 0x072f: 0xa000, + 0x0730: 0xa000, 0x0731: 0xa000, 0x0732: 0xa000, 0x0734: 0x3fbf, + 0x0737: 0x408f, 0x0738: 0x4097, 0x0739: 0x409f, 0x073a: 0x40a7, + 0x073d: 0xa000, 0x073e: 0x40af, + // Block 0x1d, offset 0x740 + 0x0740: 0x13e6, 0x0741: 0x0d6a, 0x0742: 0x1442, 0x0743: 0x140e, 0x0744: 0x0ec6, 0x0745: 0x075a, + 0x0746: 0x094e, 0x0747: 0x1696, 0x0748: 0x1696, 0x0749: 0x0a7a, 0x074a: 0x14ca, 0x074b: 0x09b2, + 0x074c: 0x0a76, 0x074d: 0x0c5e, 0x074e: 0x103e, 0x074f: 0x11ce, 0x0750: 0x1306, 0x0751: 0x1342, + 0x0752: 0x1376, 0x0753: 0x148a, 0x0754: 0x0de2, 0x0755: 0x0e6e, 0x0756: 0x0f1a, 0x0757: 0x0fb2, + 0x0758: 0x12ce, 0x0759: 0x14b2, 0x075a: 0x15de, 0x075b: 0x077e, 0x075c: 0x0922, 0x075d: 0x0df6, + 0x075e: 0x0f3e, 0x075f: 0x1302, 0x0760: 0x162e, 0x0761: 0x0b22, 0x0762: 0x0ee6, 0x0763: 0x12f2, + 0x0764: 0x1386, 0x0765: 0x0c92, 0x0766: 0x122a, 0x0767: 0x134e, 0x0768: 0x0b8e, 0x0769: 0x0d7e, + 0x076a: 0x0e86, 0x076b: 0x0f8a, 0x076c: 0x1496, 0x076d: 0x07be, 0x076e: 0x0856, 0x076f: 0x08c2, + 0x0770: 0x0cfa, 0x0771: 0x0dee, 0x0772: 0x0f3a, 0x0773: 0x105e, 0x0774: 0x11e6, 0x0775: 0x12fa, + 0x0776: 0x1312, 0x0777: 0x1436, 0x0778: 0x155a, 0x0779: 0x160e, 0x077a: 0x162a, 0x077b: 0x109a, + 0x077c: 0x10da, 0x077d: 0x1192, 0x077e: 0x12b2, 0x077f: 0x14e6, + // Block 0x1e, offset 0x780 + 0x0780: 0x1636, 0x0781: 0x13ba, 0x0782: 0x0a36, 0x0783: 0x0baa, 0x0784: 0x114a, 0x0785: 0x120a, + 0x0786: 0x0f6e, 0x0787: 0x10a2, 0x0788: 0x1406, 0x0789: 0x1552, 0x078a: 0x0a32, 0x078b: 0x0afe, + 0x078c: 0x0de6, 0x078d: 0x0e9a, 0x078e: 0x0ece, 0x078f: 0x1182, 0x0790: 0x11aa, 0x0791: 0x1512, + 0x0792: 0x08be, 0x0793: 0x1216, 0x0794: 0x0862, 0x0795: 0x085e, 0x0796: 0x1106, 0x0797: 0x1196, + 0x0798: 0x12ca, 0x0799: 0x151a, 0x079a: 0x13d6, 0x079b: 0x0c96, 0x079c: 0x0de2, 0x079d: 0x13c6, + 0x079e: 0x0766, 0x079f: 0x0ad2, 0x07a0: 0x0c02, 0x07a1: 0x0f9e, 0x07a2: 0x101e, 0x07a3: 0x08e2, + 0x07a4: 0x10aa, 0x07a5: 0x07ce, 0x07a6: 0x0be6, 0x07a7: 0x0746, 0x07a8: 0x0e5a, 0x07a9: 0x0d12, + 0x07aa: 0x117e, 0x07ab: 0x0936, 0x07ac: 0x0a22, 0x07ad: 0x106a, 0x07ae: 0x12d2, 0x07af: 0x13aa, + 0x07b0: 0x0e26, 0x07b1: 0x1466, 0x07b2: 0x0e52, 0x07b3: 0x0ca6, 0x07b4: 0x128a, 0x07b5: 0x0cc6, + 0x07b6: 0x101a, 0x07b7: 0x079a, 0x07b8: 0x0816, 0x07b9: 0x085a, 0x07ba: 0x0dc2, 0x07bb: 0x116a, + 0x07bc: 0x1262, 0x07bd: 0x13b6, 0x07be: 0x14c6, 0x07bf: 0x08ca, + // Block 0x1f, offset 0x7c0 + 0x07c0: 0x097e, 0x07c1: 0x0a86, 0x07c2: 0x0b9e, 0x07c3: 0x0d2e, 0x07c4: 0x0eea, 0x07c5: 0x10ae, + 0x07c6: 0x1502, 0x07c7: 0x15e6, 0x07c8: 0x163a, 0x07c9: 0x1652, 0x07ca: 0x08a6, 0x07cb: 0x0d62, + 0x07cc: 0x0e12, 0x07cd: 0x145a, 0x07ce: 0x0b6a, 0x07cf: 0x0c46, 0x07d0: 0x0c62, 0x07d1: 0x0cf2, + 0x07d2: 0x0eda, 0x07d3: 0x0f26, 0x07d4: 0x0fd6, 0x07d5: 0x10fa, 0x07d6: 0x119e, 0x07d7: 0x1202, + 0x07d8: 0x144a, 0x07d9: 0x12da, 0x07da: 0x1472, 0x07db: 0x14ea, 0x07dc: 0x087e, 0x07dd: 0x08aa, + 0x07de: 0x0992, 0x07df: 0x0f16, 0x07e0: 0x1362, 0x07e1: 0x13aa, 0x07e2: 0x0b8a, 0x07e3: 0x0bfa, + 0x07e4: 0x0cbe, 0x07e5: 0x0e1e, 0x07e6: 0x1146, 0x07e7: 0x0f92, 0x07e8: 0x07aa, 0x07e9: 0x09ee, + 0x07ea: 0x0ad2, 0x07eb: 0x0b36, 0x07ec: 0x0c06, 0x07ed: 0x0fae, 0x07ee: 0x0fca, 0x07ef: 0x11da, + 0x07f0: 0x11fa, 0x07f1: 0x14ce, 0x07f2: 0x154e, 0x07f3: 0x155e, 0x07f4: 0x159a, 0x07f5: 0x07c2, + 0x07f6: 0x10ee, 0x07f7: 0x14ba, 0x07f8: 0x1536, 0x07f9: 0x0c1e, 0x07fa: 0x0786, 0x07fb: 0x07e6, + 0x07fc: 0x0ad6, 0x07fd: 0x0af6, 0x07fe: 0x0d1e, 0x07ff: 0x0de2, + // Block 0x20, offset 0x800 + 0x0800: 0x0f32, 0x0801: 0x103a, 0x0802: 0x12e6, 0x0803: 0x1486, 0x0804: 0x168e, 0x0805: 0x0d52, + 0x0806: 0x150e, 0x0807: 0x08a2, 0x0808: 0x0d9e, 0x0809: 0x0daa, 0x080a: 0x0e7e, 0x080b: 0x0eb6, + 0x080c: 0x0fba, 0x080d: 0x1016, 0x080e: 0x1096, 0x080f: 0x117a, 0x0810: 0x15a6, 0x0811: 0x081e, + 0x0812: 0x0c72, 0x0813: 0x151e, 0x0814: 0x07d6, 0x0815: 0x0b1a, 0x0816: 0x0e9e, 0x0817: 0x144e, + 0x0818: 0x0bd6, 0x0819: 0x0c26, 0x081a: 0x0db2, 0x081b: 0x0f9e, 0x081c: 0x1526, 0x081d: 0x0886, + 0x081e: 0x096e, 0x081f: 0x0b06, 0x0820: 0x0d42, 0x0821: 0x0d8e, 0x0822: 0x0dce, 0x0823: 0x0e62, + 0x0824: 0x0fb6, 0x0825: 0x102a, 0x0826: 0x11c6, 0x0827: 0x1366, 0x0828: 0x1372, 0x0829: 0x14c2, + 0x082a: 0x1542, 0x082b: 0x08f2, 0x082c: 0x0eba, 0x082d: 0x0972, 0x082e: 0x0f36, 0x082f: 0x0fda, + 0x0830: 0x12f6, 0x0831: 0x152a, 0x0832: 0x1616, 0x0833: 0x163e, 0x0834: 0x0da6, 0x0835: 0x0e96, + 0x0836: 0x1232, 0x0837: 0x1126, 0x0838: 0x1132, 0x0839: 0x1156, 0x083a: 0x0f86, 0x083b: 0x0f0e, + 0x083c: 0x13d2, 0x083d: 0x07a2, 0x083e: 0x129a, 0x083f: 0x088a, + // Block 0x21, offset 0x840 + 0x0840: 0x087a, 0x0841: 0x0b7a, 0x0842: 0x0c9a, 0x0843: 0x1162, 0x0844: 0x0ac2, 0x0845: 0x0e72, + 0x0846: 0x0d5e, 0x0847: 0x1456, 0x0848: 0x1356, 0x0849: 0x1516, 0x084a: 0x1392, 0x084b: 0x0b96, + 0x084c: 0x07f6, 0x084d: 0x09ca, 0x0850: 0x0a1e, + 0x0852: 0x0d4e, 0x0855: 0x0866, 0x0856: 0x0f8e, 0x0857: 0x1052, + 0x0858: 0x10b6, 0x0859: 0x10d2, 0x085a: 0x10d6, 0x085b: 0x10ea, 0x085c: 0x1566, 0x085d: 0x115a, + 0x085e: 0x11de, 0x0860: 0x12fe, 0x0862: 0x13c2, + 0x0865: 0x1476, 0x0866: 0x14a2, + 0x086a: 0x15ba, 0x086b: 0x15be, 0x086c: 0x15c2, 0x086d: 0x1626, 0x086e: 0x149a, 0x086f: 0x1532, + 0x0870: 0x07c6, 0x0871: 0x07ea, 0x0872: 0x07fe, 0x0873: 0x08ba, 0x0874: 0x08c6, 0x0875: 0x0906, + 0x0876: 0x09ba, 0x0877: 0x09d6, 0x0878: 0x09de, 0x0879: 0x0a1a, 0x087a: 0x0a26, 0x087b: 0x0b02, + 0x087c: 0x0b0a, 0x087d: 0x0c12, 0x087e: 0x0c3a, 0x087f: 0x0c42, + // Block 0x22, offset 0x880 + 0x0880: 0x0c5a, 0x0881: 0x0d06, 0x0882: 0x0d36, 0x0883: 0x0d56, 0x0884: 0x0dc6, 0x0885: 0x0e8a, + 0x0886: 0x0ea6, 0x0887: 0x0ed6, 0x0888: 0x0f2a, 0x0889: 0x0f4a, 0x088a: 0x0fbe, 0x088b: 0x109e, + 0x088c: 0x10ba, 0x088d: 0x10c2, 0x088e: 0x10be, 0x088f: 0x10c6, 0x0890: 0x10ca, 0x0891: 0x10ce, + 0x0892: 0x10e2, 0x0893: 0x10e6, 0x0894: 0x110a, 0x0895: 0x111e, 0x0896: 0x113a, 0x0897: 0x119e, + 0x0898: 0x11a6, 0x0899: 0x11ae, 0x089a: 0x11c2, 0x089b: 0x11ea, 0x089c: 0x123a, 0x089d: 0x126e, + 0x089e: 0x126e, 0x089f: 0x12d6, 0x08a0: 0x137e, 0x08a1: 0x1396, 0x08a2: 0x13ca, 0x08a3: 0x13ce, + 0x08a4: 0x1412, 0x08a5: 0x1416, 0x08a6: 0x146e, 0x08a7: 0x1476, 0x08a8: 0x1546, 0x08a9: 0x158a, + 0x08aa: 0x15a2, 0x08ab: 0x0c0a, 0x08ac: 0x177d, 0x08ad: 0x1252, + 0x08b0: 0x074e, 0x08b1: 0x0852, 0x08b2: 0x0812, 0x08b3: 0x07ba, 0x08b4: 0x07fa, 0x08b5: 0x0826, + 0x08b6: 0x08b6, 0x08b7: 0x08d2, 0x08b8: 0x09ba, 0x08b9: 0x09a6, 0x08ba: 0x09b6, 0x08bb: 0x09d2, + 0x08bc: 0x0a1e, 0x08bd: 0x0a2e, 0x08be: 0x0a72, 0x08bf: 0x0a7e, + // Block 0x23, offset 0x8c0 + 0x08c0: 0x0a9a, 0x08c1: 0x0aaa, 0x08c2: 0x0b92, 0x08c3: 0x0b9a, 0x08c4: 0x0bca, 0x08c5: 0x0bea, + 0x08c6: 0x0c1a, 0x08c7: 0x0c32, 0x08c8: 0x0c22, 0x08c9: 0x0c42, 0x08ca: 0x0c36, 0x08cb: 0x0c5a, + 0x08cc: 0x0c76, 0x08cd: 0x0cce, 0x08ce: 0x0cda, 0x08cf: 0x0ce2, 0x08d0: 0x0d0a, 0x08d1: 0x0d4e, + 0x08d2: 0x0d7e, 0x08d3: 0x0d82, 0x08d4: 0x0d96, 0x08d5: 0x0e16, 0x08d6: 0x0e26, 0x08d7: 0x0e7e, + 0x08d8: 0x0eca, 0x08d9: 0x0ec2, 0x08da: 0x0ed6, 0x08db: 0x0ef2, 0x08dc: 0x0f2a, 0x08dd: 0x1082, + 0x08de: 0x0f4e, 0x08df: 0x0f82, 0x08e0: 0x0f8e, 0x08e1: 0x0fce, 0x08e2: 0x0fea, 0x08e3: 0x100e, + 0x08e4: 0x1032, 0x08e5: 0x1036, 0x08e6: 0x1052, 0x08e7: 0x1056, 0x08e8: 0x1066, 0x08e9: 0x107a, + 0x08ea: 0x1076, 0x08eb: 0x10a6, 0x08ec: 0x1122, 0x08ed: 0x113a, 0x08ee: 0x1152, 0x08ef: 0x118a, + 0x08f0: 0x119e, 0x08f1: 0x11ba, 0x08f2: 0x11ea, 0x08f3: 0x129e, 0x08f4: 0x12c6, 0x08f5: 0x133a, + 0x08f6: 0x1382, 0x08f7: 0x138e, 0x08f8: 0x1396, 0x08f9: 0x13ae, 0x08fa: 0x13c2, 0x08fb: 0x13b2, + 0x08fc: 0x13ca, 0x08fd: 0x13c6, 0x08fe: 0x13be, 0x08ff: 0x13ce, + // Block 0x24, offset 0x900 + 0x0900: 0x13da, 0x0901: 0x1416, 0x0902: 0x1452, 0x0903: 0x1482, 0x0904: 0x14b6, 0x0905: 0x14d6, + 0x0906: 0x1522, 0x0907: 0x1546, 0x0908: 0x1566, 0x0909: 0x157a, 0x090a: 0x158a, 0x090b: 0x1596, + 0x090c: 0x15a2, 0x090d: 0x15f6, 0x090e: 0x1696, 0x090f: 0x1714, 0x0910: 0x170f, 0x0911: 0x1741, + 0x0912: 0x0676, 0x0913: 0x069e, 0x0914: 0x06a2, 0x0915: 0x17c3, 0x0916: 0x17f0, 0x0917: 0x1868, + 0x0918: 0x1682, 0x0919: 0x1692, + // Block 0x25, offset 0x940 + 0x0940: 0x076a, 0x0941: 0x0762, 0x0942: 0x0772, 0x0943: 0x16a6, 0x0944: 0x07b6, 0x0945: 0x07c6, + 0x0946: 0x07ca, 0x0947: 0x07d2, 0x0948: 0x07da, 0x0949: 0x07de, 0x094a: 0x07ea, 0x094b: 0x07e2, + 0x094c: 0x0622, 0x094d: 0x16ba, 0x094e: 0x07fe, 0x094f: 0x0802, 0x0950: 0x0806, 0x0951: 0x0822, + 0x0952: 0x16ab, 0x0953: 0x0626, 0x0954: 0x080e, 0x0955: 0x082e, 0x0956: 0x16b5, 0x0957: 0x083e, + 0x0958: 0x0846, 0x0959: 0x07a6, 0x095a: 0x084e, 0x095b: 0x0852, 0x095c: 0x1890, 0x095d: 0x086e, + 0x095e: 0x0876, 0x095f: 0x062e, 0x0960: 0x088e, 0x0961: 0x0892, 0x0962: 0x089a, 0x0963: 0x089e, + 0x0964: 0x0632, 0x0965: 0x08b6, 0x0966: 0x08ba, 0x0967: 0x08c6, 0x0968: 0x08d2, 0x0969: 0x08d6, + 0x096a: 0x08da, 0x096b: 0x08e2, 0x096c: 0x0902, 0x096d: 0x0906, 0x096e: 0x090e, 0x096f: 0x091e, + 0x0970: 0x0926, 0x0971: 0x092a, 0x0972: 0x092a, 0x0973: 0x092a, 0x0974: 0x16c9, 0x0975: 0x0f02, + 0x0976: 0x093e, 0x0977: 0x0946, 0x0978: 0x16ce, 0x0979: 0x0952, 0x097a: 0x095a, 0x097b: 0x0962, + 0x097c: 0x098a, 0x097d: 0x0976, 0x097e: 0x0982, 0x097f: 0x0986, + // Block 0x26, offset 0x980 + 0x0980: 0x098e, 0x0981: 0x0996, 0x0982: 0x099a, 0x0983: 0x09a2, 0x0984: 0x09aa, 0x0985: 0x09ae, + 0x0986: 0x09ae, 0x0987: 0x09b6, 0x0988: 0x09be, 0x0989: 0x09c2, 0x098a: 0x09ce, 0x098b: 0x09f2, + 0x098c: 0x09d6, 0x098d: 0x09f6, 0x098e: 0x09da, 0x098f: 0x09e2, 0x0990: 0x087a, 0x0991: 0x0a3e, + 0x0992: 0x0a06, 0x0993: 0x0a0a, 0x0994: 0x0a0e, 0x0995: 0x0a02, 0x0996: 0x0a16, 0x0997: 0x0a12, + 0x0998: 0x0a2a, 0x0999: 0x16d3, 0x099a: 0x0a46, 0x099b: 0x0a4a, 0x099c: 0x0a52, 0x099d: 0x0a5e, + 0x099e: 0x0a66, 0x099f: 0x0a82, 0x09a0: 0x16d8, 0x09a1: 0x16dd, 0x09a2: 0x0a8e, 0x09a3: 0x0a92, + 0x09a4: 0x0a96, 0x09a5: 0x0a8a, 0x09a6: 0x0a9e, 0x09a7: 0x0636, 0x09a8: 0x063a, 0x09a9: 0x0aa6, + 0x09aa: 0x0aae, 0x09ab: 0x0aae, 0x09ac: 0x16e2, 0x09ad: 0x0aca, 0x09ae: 0x0ace, 0x09af: 0x0ad2, + 0x09b0: 0x0ada, 0x09b1: 0x16e7, 0x09b2: 0x0ae2, 0x09b3: 0x0ae6, 0x09b4: 0x0bbe, 0x09b5: 0x0aee, + 0x09b6: 0x063e, 0x09b7: 0x0afa, 0x09b8: 0x0b0a, 0x09b9: 0x0b16, 0x09ba: 0x0b12, 0x09bb: 0x16f1, + 0x09bc: 0x0b1e, 0x09bd: 0x16f6, 0x09be: 0x0b2a, 0x09bf: 0x0b26, + // Block 0x27, offset 0x9c0 + 0x09c0: 0x0b2e, 0x09c1: 0x0b3e, 0x09c2: 0x0b42, 0x09c3: 0x0642, 0x09c4: 0x0b52, 0x09c5: 0x0b5a, + 0x09c6: 0x0b5e, 0x09c7: 0x0b62, 0x09c8: 0x0646, 0x09c9: 0x16fb, 0x09ca: 0x064a, 0x09cb: 0x0b7e, + 0x09cc: 0x0b82, 0x09cd: 0x0b86, 0x09ce: 0x0b8e, 0x09cf: 0x18c2, 0x09d0: 0x0ba6, 0x09d1: 0x1705, + 0x09d2: 0x1705, 0x09d3: 0x1246, 0x09d4: 0x0bb6, 0x09d5: 0x0bb6, 0x09d6: 0x064e, 0x09d7: 0x1728, + 0x09d8: 0x17fa, 0x09d9: 0x0bc6, 0x09da: 0x0bce, 0x09db: 0x0652, 0x09dc: 0x0be2, 0x09dd: 0x0bf2, + 0x09de: 0x0bf6, 0x09df: 0x0bfe, 0x09e0: 0x0c0e, 0x09e1: 0x065a, 0x09e2: 0x0656, 0x09e3: 0x0c12, + 0x09e4: 0x170a, 0x09e5: 0x0c16, 0x09e6: 0x0c2a, 0x09e7: 0x0c2e, 0x09e8: 0x0c32, 0x09e9: 0x0c2e, + 0x09ea: 0x0c3e, 0x09eb: 0x0c42, 0x09ec: 0x0c52, 0x09ed: 0x0c4a, 0x09ee: 0x0c4e, 0x09ef: 0x0c56, + 0x09f0: 0x0c5a, 0x09f1: 0x0c5e, 0x09f2: 0x0c6a, 0x09f3: 0x0c6e, 0x09f4: 0x0c86, 0x09f5: 0x0c8e, + 0x09f6: 0x0c9e, 0x09f7: 0x0cb2, 0x09f8: 0x1719, 0x09f9: 0x0cae, 0x09fa: 0x0ca2, 0x09fb: 0x0cba, + 0x09fc: 0x0cc2, 0x09fd: 0x0cd6, 0x09fe: 0x171e, 0x09ff: 0x0cde, + // Block 0x28, offset 0xa00 + 0x0a00: 0x0cd2, 0x0a01: 0x0cca, 0x0a02: 0x065e, 0x0a03: 0x0ce6, 0x0a04: 0x0cee, 0x0a05: 0x0cf6, + 0x0a06: 0x0cea, 0x0a07: 0x0662, 0x0a08: 0x0d06, 0x0a09: 0x0d0e, 0x0a0a: 0x1723, 0x0a0b: 0x0d3a, + 0x0a0c: 0x0d6e, 0x0a0d: 0x0d4a, 0x0a0e: 0x066e, 0x0a0f: 0x0d56, 0x0a10: 0x066a, 0x0a11: 0x0666, + 0x0a12: 0x0832, 0x0a13: 0x0836, 0x0a14: 0x0d72, 0x0a15: 0x0d5a, 0x0a16: 0x121a, 0x0a17: 0x06d2, + 0x0a18: 0x0d7e, 0x0a19: 0x0d82, 0x0a1a: 0x0d86, 0x0a1b: 0x0d9a, 0x0a1c: 0x0d92, 0x0a1d: 0x173c, + 0x0a1e: 0x0672, 0x0a1f: 0x0dae, 0x0a20: 0x0da2, 0x0a21: 0x0dbe, 0x0a22: 0x0dc6, 0x0a23: 0x1746, + 0x0a24: 0x0dca, 0x0a25: 0x0db6, 0x0a26: 0x0dd2, 0x0a27: 0x0676, 0x0a28: 0x0dd6, 0x0a29: 0x0dda, + 0x0a2a: 0x0dde, 0x0a2b: 0x0dea, 0x0a2c: 0x174b, 0x0a2d: 0x0df2, 0x0a2e: 0x067a, 0x0a2f: 0x0dfe, + 0x0a30: 0x1750, 0x0a31: 0x0e02, 0x0a32: 0x067e, 0x0a33: 0x0e0e, 0x0a34: 0x0e1a, 0x0a35: 0x0e26, + 0x0a36: 0x0e2a, 0x0a37: 0x1755, 0x0a38: 0x16ec, 0x0a39: 0x175a, 0x0a3a: 0x0e4a, 0x0a3b: 0x175f, + 0x0a3c: 0x0e56, 0x0a3d: 0x0e5e, 0x0a3e: 0x0e4e, 0x0a3f: 0x0e6a, + // Block 0x29, offset 0xa40 + 0x0a40: 0x0e7a, 0x0a41: 0x0e8a, 0x0a42: 0x0e7e, 0x0a43: 0x0e82, 0x0a44: 0x0e8e, 0x0a45: 0x0e92, + 0x0a46: 0x1764, 0x0a47: 0x0e76, 0x0a48: 0x0eaa, 0x0a49: 0x0eae, 0x0a4a: 0x0682, 0x0a4b: 0x0ec2, + 0x0a4c: 0x0ebe, 0x0a4d: 0x1769, 0x0a4e: 0x0ea2, 0x0a4f: 0x0ede, 0x0a50: 0x176e, 0x0a51: 0x1773, + 0x0a52: 0x0ee2, 0x0a53: 0x0ef6, 0x0a54: 0x0ef2, 0x0a55: 0x0eee, 0x0a56: 0x0686, 0x0a57: 0x0efa, + 0x0a58: 0x0f0a, 0x0a59: 0x0f06, 0x0a5a: 0x0f12, 0x0a5b: 0x16b0, 0x0a5c: 0x0f22, 0x0a5d: 0x1778, + 0x0a5e: 0x0f2e, 0x0a5f: 0x1782, 0x0a60: 0x0f42, 0x0a61: 0x0f4e, 0x0a62: 0x0f62, 0x0a63: 0x1787, + 0x0a64: 0x0f76, 0x0a65: 0x0f7a, 0x0a66: 0x178c, 0x0a67: 0x1791, 0x0a68: 0x0f96, 0x0a69: 0x0fa6, + 0x0a6a: 0x068a, 0x0a6b: 0x0faa, 0x0a6c: 0x068e, 0x0a6d: 0x068e, 0x0a6e: 0x0fc2, 0x0a6f: 0x0fc6, + 0x0a70: 0x0fce, 0x0a71: 0x0fd2, 0x0a72: 0x0fde, 0x0a73: 0x0692, 0x0a74: 0x0ff6, 0x0a75: 0x1796, + 0x0a76: 0x1012, 0x0a77: 0x179b, 0x0a78: 0x101e, 0x0a79: 0x1700, 0x0a7a: 0x102e, 0x0a7b: 0x17a0, + 0x0a7c: 0x17a5, 0x0a7d: 0x17aa, 0x0a7e: 0x0696, 0x0a7f: 0x069a, + // Block 0x2a, offset 0xa80 + 0x0a80: 0x1066, 0x0a81: 0x17b4, 0x0a82: 0x17af, 0x0a83: 0x17b9, 0x0a84: 0x17be, 0x0a85: 0x106e, + 0x0a86: 0x1072, 0x0a87: 0x1072, 0x0a88: 0x107a, 0x0a89: 0x06a2, 0x0a8a: 0x107e, 0x0a8b: 0x06a6, + 0x0a8c: 0x06aa, 0x0a8d: 0x17c8, 0x0a8e: 0x1092, 0x0a8f: 0x109a, 0x0a90: 0x10a6, 0x0a91: 0x06ae, + 0x0a92: 0x17cd, 0x0a93: 0x10ca, 0x0a94: 0x17d2, 0x0a95: 0x17d7, 0x0a96: 0x10ea, 0x0a97: 0x1102, + 0x0a98: 0x06b2, 0x0a99: 0x110a, 0x0a9a: 0x110e, 0x0a9b: 0x1112, 0x0a9c: 0x17dc, 0x0a9d: 0x17e1, + 0x0a9e: 0x17e1, 0x0a9f: 0x112a, 0x0aa0: 0x06b6, 0x0aa1: 0x17e6, 0x0aa2: 0x113e, 0x0aa3: 0x1142, + 0x0aa4: 0x06ba, 0x0aa5: 0x17eb, 0x0aa6: 0x115e, 0x0aa7: 0x06be, 0x0aa8: 0x116e, 0x0aa9: 0x1166, + 0x0aaa: 0x1176, 0x0aab: 0x17f5, 0x0aac: 0x118e, 0x0aad: 0x06c2, 0x0aae: 0x119a, 0x0aaf: 0x11a2, + 0x0ab0: 0x11b2, 0x0ab1: 0x06c6, 0x0ab2: 0x17ff, 0x0ab3: 0x1804, 0x0ab4: 0x06ca, 0x0ab5: 0x1809, + 0x0ab6: 0x11ca, 0x0ab7: 0x180e, 0x0ab8: 0x11d6, 0x0ab9: 0x11e2, 0x0aba: 0x11ea, 0x0abb: 0x1813, + 0x0abc: 0x1818, 0x0abd: 0x11fe, 0x0abe: 0x181d, 0x0abf: 0x1206, + // Block 0x2b, offset 0xac0 + 0x0ac0: 0x172d, 0x0ac1: 0x06ce, 0x0ac2: 0x121e, 0x0ac3: 0x1222, 0x0ac4: 0x06d6, 0x0ac5: 0x1226, + 0x0ac6: 0x0aa2, 0x0ac7: 0x1822, 0x0ac8: 0x1827, 0x0ac9: 0x1732, 0x0aca: 0x1737, 0x0acb: 0x1246, + 0x0acc: 0x124a, 0x0acd: 0x1462, 0x0ace: 0x06da, 0x0acf: 0x1276, 0x0ad0: 0x1272, 0x0ad1: 0x127a, + 0x0ad2: 0x08ae, 0x0ad3: 0x127e, 0x0ad4: 0x1282, 0x0ad5: 0x1286, 0x0ad6: 0x128e, 0x0ad7: 0x182c, + 0x0ad8: 0x128a, 0x0ad9: 0x1292, 0x0ada: 0x12a6, 0x0adb: 0x12aa, 0x0adc: 0x1296, 0x0add: 0x12ae, + 0x0ade: 0x12c2, 0x0adf: 0x12d6, 0x0ae0: 0x12a2, 0x0ae1: 0x12b6, 0x0ae2: 0x12ba, 0x0ae3: 0x12be, + 0x0ae4: 0x1831, 0x0ae5: 0x183b, 0x0ae6: 0x1836, 0x0ae7: 0x06de, 0x0ae8: 0x12de, 0x0ae9: 0x12e2, + 0x0aea: 0x12ea, 0x0aeb: 0x184f, 0x0aec: 0x12ee, 0x0aed: 0x1840, 0x0aee: 0x06e2, 0x0aef: 0x06e6, + 0x0af0: 0x1845, 0x0af1: 0x184a, 0x0af2: 0x06ea, 0x0af3: 0x130e, 0x0af4: 0x1312, 0x0af5: 0x1316, + 0x0af6: 0x131a, 0x0af7: 0x1326, 0x0af8: 0x1322, 0x0af9: 0x132e, 0x0afa: 0x132a, 0x0afb: 0x133a, + 0x0afc: 0x1332, 0x0afd: 0x1336, 0x0afe: 0x133e, 0x0aff: 0x06ee, + // Block 0x2c, offset 0xb00 + 0x0b00: 0x1346, 0x0b01: 0x134a, 0x0b02: 0x06f2, 0x0b03: 0x135a, 0x0b04: 0x135e, 0x0b05: 0x1854, + 0x0b06: 0x136a, 0x0b07: 0x136e, 0x0b08: 0x06f6, 0x0b09: 0x137a, 0x0b0a: 0x062a, 0x0b0b: 0x1859, + 0x0b0c: 0x185e, 0x0b0d: 0x06fa, 0x0b0e: 0x06fe, 0x0b0f: 0x13a6, 0x0b10: 0x13be, 0x0b11: 0x13da, + 0x0b12: 0x13ea, 0x0b13: 0x1863, 0x0b14: 0x13fe, 0x0b15: 0x1402, 0x0b16: 0x141a, 0x0b17: 0x1426, + 0x0b18: 0x186d, 0x0b19: 0x16bf, 0x0b1a: 0x1432, 0x0b1b: 0x142e, 0x0b1c: 0x143a, 0x0b1d: 0x16c4, + 0x0b1e: 0x1446, 0x0b1f: 0x1452, 0x0b20: 0x1872, 0x0b21: 0x1877, 0x0b22: 0x1492, 0x0b23: 0x149e, + 0x0b24: 0x14a6, 0x0b25: 0x187c, 0x0b26: 0x14aa, 0x0b27: 0x14d2, 0x0b28: 0x14de, 0x0b29: 0x14e2, + 0x0b2a: 0x14da, 0x0b2b: 0x14ee, 0x0b2c: 0x14f2, 0x0b2d: 0x1881, 0x0b2e: 0x14fe, 0x0b2f: 0x0702, + 0x0b30: 0x1506, 0x0b31: 0x1886, 0x0b32: 0x0706, 0x0b33: 0x153e, 0x0b34: 0x0b32, 0x0b35: 0x1556, + 0x0b36: 0x188b, 0x0b37: 0x1895, 0x0b38: 0x070a, 0x0b39: 0x070e, 0x0b3a: 0x157e, 0x0b3b: 0x189a, + 0x0b3c: 0x0712, 0x0b3d: 0x189f, 0x0b3e: 0x1596, 0x0b3f: 0x1596, + // Block 0x2d, offset 0xb40 + 0x0b40: 0x159e, 0x0b41: 0x18a4, 0x0b42: 0x15b6, 0x0b43: 0x0716, 0x0b44: 0x15c6, 0x0b45: 0x15d2, + 0x0b46: 0x15da, 0x0b47: 0x15e2, 0x0b48: 0x071a, 0x0b49: 0x18a9, 0x0b4a: 0x15f6, 0x0b4b: 0x1612, + 0x0b4c: 0x161e, 0x0b4d: 0x071e, 0x0b4e: 0x0722, 0x0b4f: 0x1622, 0x0b50: 0x18ae, 0x0b51: 0x0726, + 0x0b52: 0x18b3, 0x0b53: 0x18b8, 0x0b54: 0x18bd, 0x0b55: 0x1646, 0x0b56: 0x072a, 0x0b57: 0x165a, + 0x0b58: 0x1662, 0x0b59: 0x1666, 0x0b5a: 0x166e, 0x0b5b: 0x1676, 0x0b5c: 0x167e, 0x0b5d: 0x18c7, +} + +// nfcSparseOffset: 118 entries, 236 bytes +var nfcSparseOffset = []uint16{0x0, 0x5, 0x9, 0xb, 0xd, 0x18, 0x28, 0x2a, 0x2f, 0x3a, 0x49, 0x56, 0x5e, 0x62, 0x67, 0x69, 0x78, 0x80, 0x87, 0x8a, 0x92, 0x96, 0x9a, 0x9c, 0x9e, 0xa7, 0xab, 0xb2, 0xb7, 0xba, 0xc4, 0xc6, 0xcd, 0xd5, 0xd8, 0xda, 0xdc, 0xde, 0xe3, 0xf4, 0x100, 0x102, 0x108, 0x10a, 0x10c, 0x10e, 0x110, 0x112, 0x114, 0x117, 0x11a, 0x11c, 0x11f, 0x122, 0x126, 0x12f, 0x131, 0x134, 0x136, 0x140, 0x14f, 0x153, 0x161, 0x164, 0x16a, 0x170, 0x17b, 0x17f, 0x181, 0x183, 0x185, 0x187, 0x189, 0x18f, 0x197, 0x19b, 0x19e, 0x1a0, 0x1a2, 0x1a4, 0x1a7, 0x1a9, 0x1ab, 0x1ad, 0x1af, 0x1b5, 0x1b8, 0x1ba, 0x1c1, 0x1c7, 0x1cd, 0x1d5, 0x1db, 0x1e1, 0x1e7, 0x1eb, 0x1f9, 0x202, 0x205, 0x208, 0x20a, 0x20d, 0x20f, 0x211, 0x216, 0x218, 0x21a, 0x21c, 0x21e, 0x220, 0x226, 0x22e, 0x235, 0x238, 0x245, 0x24f, 0x251, 0x253} + +// nfcSparseValues: 597 entries, 2388 bytes +var nfcSparseValues = [597]valueRange{ + // Block 0x0, offset 0x1 + {value: 0x0000, lo: 0x04}, + {value: 0xa100, lo: 0xa8, hi: 0xa8}, + {value: 0x8100, lo: 0xaf, hi: 0xaf}, + {value: 0x8100, lo: 0xb4, hi: 0xb4}, + {value: 0x8100, lo: 0xb8, hi: 0xb8}, + // Block 0x1, offset 0x2 + {value: 0x0091, lo: 0x03}, + {value: 0x46c9, lo: 0xa0, hi: 0xa1}, + {value: 0x46fb, lo: 0xaf, hi: 0xb0}, + {value: 0xa000, lo: 0xb7, hi: 0xb7}, + // Block 0x2, offset 0x3 + {value: 0x0000, lo: 0x01}, + {value: 0xa000, lo: 0x92, hi: 0x92}, + // Block 0x3, offset 0x4 + {value: 0x0000, lo: 0x01}, + {value: 0x8100, lo: 0x98, hi: 0x9d}, + // Block 0x4, offset 0x5 + {value: 0x0006, lo: 0x0a}, + {value: 0xa000, lo: 0x81, hi: 0x81}, + {value: 0xa000, lo: 0x85, hi: 0x85}, + {value: 0xa000, lo: 0x89, hi: 0x89}, + {value: 0x4827, lo: 0x8a, hi: 0x8a}, + {value: 0x4845, lo: 0x8b, hi: 0x8b}, + {value: 0x36ae, lo: 0x8c, hi: 0x8c}, + {value: 0x36c6, lo: 0x8d, hi: 0x8d}, + {value: 0x485d, lo: 0x8e, hi: 0x8e}, + {value: 0xa000, lo: 0x92, hi: 0x92}, + {value: 0x36e4, lo: 0x93, hi: 0x94}, + // Block 0x5, offset 0x6 + {value: 0x0000, lo: 0x0f}, + {value: 0xa000, lo: 0x83, hi: 0x83}, + {value: 0xa000, lo: 0x87, hi: 0x87}, + {value: 0xa000, lo: 0x8b, hi: 0x8b}, + {value: 0xa000, lo: 0x8d, hi: 0x8d}, + {value: 0x378c, lo: 0x90, hi: 0x90}, + {value: 0x3798, lo: 0x91, hi: 0x91}, + {value: 0x3786, lo: 0x93, hi: 0x93}, + {value: 0xa000, lo: 0x96, hi: 0x96}, + {value: 0x37fe, lo: 0x97, hi: 0x97}, + {value: 0x37c8, lo: 0x9c, hi: 0x9c}, + {value: 0x37b0, lo: 0x9d, hi: 0x9d}, + {value: 0x37da, lo: 0x9e, hi: 0x9e}, + {value: 0xa000, lo: 0xb4, hi: 0xb5}, + {value: 0x3804, lo: 0xb6, hi: 0xb6}, + {value: 0x380a, lo: 0xb7, hi: 0xb7}, + // Block 0x6, offset 0x7 + {value: 0x0000, lo: 0x01}, + {value: 0x8132, lo: 0x83, hi: 0x87}, + // Block 0x7, offset 0x8 + {value: 0x0001, lo: 0x04}, + {value: 0x8113, lo: 0x81, hi: 0x82}, + {value: 0x8132, lo: 0x84, hi: 0x84}, + {value: 0x812d, lo: 0x85, hi: 0x85}, + {value: 0x810d, lo: 0x87, hi: 0x87}, + // Block 0x8, offset 0x9 + {value: 0x0000, lo: 0x0a}, + {value: 0x8132, lo: 0x90, hi: 0x97}, + {value: 0x8119, lo: 0x98, hi: 0x98}, + {value: 0x811a, lo: 0x99, hi: 0x99}, + {value: 0x811b, lo: 0x9a, hi: 0x9a}, + {value: 0x3828, lo: 0xa2, hi: 0xa2}, + {value: 0x382e, lo: 0xa3, hi: 0xa3}, + {value: 0x383a, lo: 0xa4, hi: 0xa4}, + {value: 0x3834, lo: 0xa5, hi: 0xa5}, + {value: 0x3840, lo: 0xa6, hi: 0xa6}, + {value: 0xa000, lo: 0xa7, hi: 0xa7}, + // Block 0x9, offset 0xa + {value: 0x0000, lo: 0x0e}, + {value: 0x3852, lo: 0x80, hi: 0x80}, + {value: 0xa000, lo: 0x81, hi: 0x81}, + {value: 0x3846, lo: 0x82, hi: 0x82}, + {value: 0xa000, lo: 0x92, hi: 0x92}, + {value: 0x384c, lo: 0x93, hi: 0x93}, + {value: 0xa000, lo: 0x95, hi: 0x95}, + {value: 0x8132, lo: 0x96, hi: 0x9c}, + {value: 0x8132, lo: 0x9f, hi: 0xa2}, + {value: 0x812d, lo: 0xa3, hi: 0xa3}, + {value: 0x8132, lo: 0xa4, hi: 0xa4}, + {value: 0x8132, lo: 0xa7, hi: 0xa8}, + {value: 0x812d, lo: 0xaa, hi: 0xaa}, + {value: 0x8132, lo: 0xab, hi: 0xac}, + {value: 0x812d, lo: 0xad, hi: 0xad}, + // Block 0xa, offset 0xb + {value: 0x0000, lo: 0x0c}, + {value: 0x811f, lo: 0x91, hi: 0x91}, + {value: 0x8132, lo: 0xb0, hi: 0xb0}, + {value: 0x812d, lo: 0xb1, hi: 0xb1}, + {value: 0x8132, lo: 0xb2, hi: 0xb3}, + {value: 0x812d, lo: 0xb4, hi: 0xb4}, + {value: 0x8132, lo: 0xb5, hi: 0xb6}, + {value: 0x812d, lo: 0xb7, hi: 0xb9}, + {value: 0x8132, lo: 0xba, hi: 0xba}, + {value: 0x812d, lo: 0xbb, hi: 0xbc}, + {value: 0x8132, lo: 0xbd, hi: 0xbd}, + {value: 0x812d, lo: 0xbe, hi: 0xbe}, + {value: 0x8132, lo: 0xbf, hi: 0xbf}, + // Block 0xb, offset 0xc + {value: 0x0005, lo: 0x07}, + {value: 0x8132, lo: 0x80, hi: 0x80}, + {value: 0x8132, lo: 0x81, hi: 0x81}, + {value: 0x812d, lo: 0x82, hi: 0x83}, + {value: 0x812d, lo: 0x84, hi: 0x85}, + {value: 0x812d, lo: 0x86, hi: 0x87}, + {value: 0x812d, lo: 0x88, hi: 0x89}, + {value: 0x8132, lo: 0x8a, hi: 0x8a}, + // Block 0xc, offset 0xd + {value: 0x0000, lo: 0x03}, + {value: 0x8132, lo: 0xab, hi: 0xb1}, + {value: 0x812d, lo: 0xb2, hi: 0xb2}, + {value: 0x8132, lo: 0xb3, hi: 0xb3}, + // Block 0xd, offset 0xe + {value: 0x0000, lo: 0x04}, + {value: 0x8132, lo: 0x96, hi: 0x99}, + {value: 0x8132, lo: 0x9b, hi: 0xa3}, + {value: 0x8132, lo: 0xa5, hi: 0xa7}, + {value: 0x8132, lo: 0xa9, hi: 0xad}, + // Block 0xe, offset 0xf + {value: 0x0000, lo: 0x01}, + {value: 0x812d, lo: 0x99, hi: 0x9b}, + // Block 0xf, offset 0x10 + {value: 0x0000, lo: 0x0e}, + {value: 0x8132, lo: 0xa4, hi: 0xa5}, + {value: 0x812d, lo: 0xa6, hi: 0xa6}, + {value: 0x8132, lo: 0xa7, hi: 0xa8}, + {value: 0x812d, lo: 0xa9, hi: 0xa9}, + {value: 0x8132, lo: 0xaa, hi: 0xac}, + {value: 0x812d, lo: 0xad, hi: 0xaf}, + {value: 0x8116, lo: 0xb0, hi: 0xb0}, + {value: 0x8117, lo: 0xb1, hi: 0xb1}, + {value: 0x8118, lo: 0xb2, hi: 0xb2}, + {value: 0x8132, lo: 0xb3, hi: 0xb5}, + {value: 0x812d, lo: 0xb6, hi: 0xb6}, + {value: 0x8132, lo: 0xb7, hi: 0xb8}, + {value: 0x812d, lo: 0xb9, hi: 0xba}, + {value: 0x8132, lo: 0xbb, hi: 0xbe}, + // Block 0x10, offset 0x11 + {value: 0x0000, lo: 0x07}, + {value: 0xa000, lo: 0xa8, hi: 0xa8}, + {value: 0x3ebf, lo: 0xa9, hi: 0xa9}, + {value: 0xa000, lo: 0xb0, hi: 0xb0}, + {value: 0x3ec7, lo: 0xb1, hi: 0xb1}, + {value: 0xa000, lo: 0xb3, hi: 0xb3}, + {value: 0x3ecf, lo: 0xb4, hi: 0xb4}, + {value: 0x9902, lo: 0xbc, hi: 0xbc}, + // Block 0x11, offset 0x12 + {value: 0x0008, lo: 0x06}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + {value: 0x8132, lo: 0x91, hi: 0x91}, + {value: 0x812d, lo: 0x92, hi: 0x92}, + {value: 0x8132, lo: 0x93, hi: 0x93}, + {value: 0x8132, lo: 0x94, hi: 0x94}, + {value: 0x4503, lo: 0x98, hi: 0x9f}, + // Block 0x12, offset 0x13 + {value: 0x0000, lo: 0x02}, + {value: 0x8102, lo: 0xbc, hi: 0xbc}, + {value: 0x9900, lo: 0xbe, hi: 0xbe}, + // Block 0x13, offset 0x14 + {value: 0x0007, lo: 0x07}, + {value: 0xa000, lo: 0x87, hi: 0x87}, + {value: 0x18cc, lo: 0x8b, hi: 0x8c}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + {value: 0x9900, lo: 0x97, hi: 0x97}, + {value: 0x4543, lo: 0x9c, hi: 0x9c}, + {value: 0x454b, lo: 0x9d, hi: 0x9d}, + {value: 0x4553, lo: 0x9f, hi: 0x9f}, + // Block 0x14, offset 0x15 + {value: 0x0000, lo: 0x03}, + {value: 0x457b, lo: 0xb3, hi: 0xb3}, + {value: 0x4583, lo: 0xb6, hi: 0xb6}, + {value: 0x8102, lo: 0xbc, hi: 0xbc}, + // Block 0x15, offset 0x16 + {value: 0x0008, lo: 0x03}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + {value: 0x455b, lo: 0x99, hi: 0x9b}, + {value: 0x4573, lo: 0x9e, hi: 0x9e}, + // Block 0x16, offset 0x17 + {value: 0x0000, lo: 0x01}, + {value: 0x8102, lo: 0xbc, hi: 0xbc}, + // Block 0x17, offset 0x18 + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + // Block 0x18, offset 0x19 + {value: 0x0000, lo: 0x08}, + {value: 0xa000, lo: 0x87, hi: 0x87}, + {value: 0x18e1, lo: 0x88, hi: 0x88}, + {value: 0x18da, lo: 0x8b, hi: 0x8b}, + {value: 0x18e8, lo: 0x8c, hi: 0x8c}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + {value: 0x9900, lo: 0x96, hi: 0x97}, + {value: 0x458b, lo: 0x9c, hi: 0x9c}, + {value: 0x4593, lo: 0x9d, hi: 0x9d}, + // Block 0x19, offset 0x1a + {value: 0x0000, lo: 0x03}, + {value: 0xa000, lo: 0x92, hi: 0x92}, + {value: 0x18ef, lo: 0x94, hi: 0x94}, + {value: 0x9900, lo: 0xbe, hi: 0xbe}, + // Block 0x1a, offset 0x1b + {value: 0x0000, lo: 0x06}, + {value: 0xa000, lo: 0x86, hi: 0x87}, + {value: 0x18f6, lo: 0x8a, hi: 0x8a}, + {value: 0x1904, lo: 0x8b, hi: 0x8b}, + {value: 0x18fd, lo: 0x8c, hi: 0x8c}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + {value: 0x9900, lo: 0x97, hi: 0x97}, + // Block 0x1b, offset 0x1c + {value: 0x1801, lo: 0x04}, + {value: 0xa000, lo: 0x86, hi: 0x86}, + {value: 0x3ed7, lo: 0x88, hi: 0x88}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + {value: 0x8120, lo: 0x95, hi: 0x96}, + // Block 0x1c, offset 0x1d + {value: 0x0000, lo: 0x02}, + {value: 0x8102, lo: 0xbc, hi: 0xbc}, + {value: 0xa000, lo: 0xbf, hi: 0xbf}, + // Block 0x1d, offset 0x1e + {value: 0x0000, lo: 0x09}, + {value: 0x190b, lo: 0x80, hi: 0x80}, + {value: 0x9900, lo: 0x82, hi: 0x82}, + {value: 0xa000, lo: 0x86, hi: 0x86}, + {value: 0x1912, lo: 0x87, hi: 0x87}, + {value: 0x1919, lo: 0x88, hi: 0x88}, + {value: 0x2e63, lo: 0x8a, hi: 0x8a}, + {value: 0x19a2, lo: 0x8b, hi: 0x8b}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + {value: 0x9900, lo: 0x95, hi: 0x96}, + // Block 0x1e, offset 0x1f + {value: 0x0000, lo: 0x01}, + {value: 0x9900, lo: 0xbe, hi: 0xbe}, + // Block 0x1f, offset 0x20 + {value: 0x0000, lo: 0x06}, + {value: 0xa000, lo: 0x86, hi: 0x87}, + {value: 0x1920, lo: 0x8a, hi: 0x8a}, + {value: 0x192e, lo: 0x8b, hi: 0x8b}, + {value: 0x1927, lo: 0x8c, hi: 0x8c}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + {value: 0x9900, lo: 0x97, hi: 0x97}, + // Block 0x20, offset 0x21 + {value: 0x0007, lo: 0x07}, + {value: 0x9904, lo: 0x8a, hi: 0x8a}, + {value: 0x9900, lo: 0x8f, hi: 0x8f}, + {value: 0xa000, lo: 0x99, hi: 0x99}, + {value: 0x3edf, lo: 0x9a, hi: 0x9a}, + {value: 0x2e6a, lo: 0x9c, hi: 0x9d}, + {value: 0x1935, lo: 0x9e, hi: 0x9e}, + {value: 0x9900, lo: 0x9f, hi: 0x9f}, + // Block 0x21, offset 0x22 + {value: 0x0000, lo: 0x02}, + {value: 0x8122, lo: 0xb8, hi: 0xb9}, + {value: 0x8104, lo: 0xba, hi: 0xba}, + // Block 0x22, offset 0x23 + {value: 0x0000, lo: 0x01}, + {value: 0x8123, lo: 0x88, hi: 0x8b}, + // Block 0x23, offset 0x24 + {value: 0x0000, lo: 0x01}, + {value: 0x8124, lo: 0xb8, hi: 0xb9}, + // Block 0x24, offset 0x25 + {value: 0x0000, lo: 0x01}, + {value: 0x8125, lo: 0x88, hi: 0x8b}, + // Block 0x25, offset 0x26 + {value: 0x0000, lo: 0x04}, + {value: 0x812d, lo: 0x98, hi: 0x99}, + {value: 0x812d, lo: 0xb5, hi: 0xb5}, + {value: 0x812d, lo: 0xb7, hi: 0xb7}, + {value: 0x812b, lo: 0xb9, hi: 0xb9}, + // Block 0x26, offset 0x27 + {value: 0x0000, lo: 0x10}, + {value: 0x2783, lo: 0x83, hi: 0x83}, + {value: 0x278a, lo: 0x8d, hi: 0x8d}, + {value: 0x2791, lo: 0x92, hi: 0x92}, + {value: 0x2798, lo: 0x97, hi: 0x97}, + {value: 0x279f, lo: 0x9c, hi: 0x9c}, + {value: 0x277c, lo: 0xa9, hi: 0xa9}, + {value: 0x8126, lo: 0xb1, hi: 0xb1}, + {value: 0x8127, lo: 0xb2, hi: 0xb2}, + {value: 0x49b7, lo: 0xb3, hi: 0xb3}, + {value: 0x8128, lo: 0xb4, hi: 0xb4}, + {value: 0x49c0, lo: 0xb5, hi: 0xb5}, + {value: 0x459b, lo: 0xb6, hi: 0xb6}, + {value: 0x8200, lo: 0xb7, hi: 0xb7}, + {value: 0x45a3, lo: 0xb8, hi: 0xb8}, + {value: 0x8200, lo: 0xb9, hi: 0xb9}, + {value: 0x8127, lo: 0xba, hi: 0xbd}, + // Block 0x27, offset 0x28 + {value: 0x0000, lo: 0x0b}, + {value: 0x8127, lo: 0x80, hi: 0x80}, + {value: 0x49c9, lo: 0x81, hi: 0x81}, + {value: 0x8132, lo: 0x82, hi: 0x83}, + {value: 0x8104, lo: 0x84, hi: 0x84}, + {value: 0x8132, lo: 0x86, hi: 0x87}, + {value: 0x27ad, lo: 0x93, hi: 0x93}, + {value: 0x27b4, lo: 0x9d, hi: 0x9d}, + {value: 0x27bb, lo: 0xa2, hi: 0xa2}, + {value: 0x27c2, lo: 0xa7, hi: 0xa7}, + {value: 0x27c9, lo: 0xac, hi: 0xac}, + {value: 0x27a6, lo: 0xb9, hi: 0xb9}, + // Block 0x28, offset 0x29 + {value: 0x0000, lo: 0x01}, + {value: 0x812d, lo: 0x86, hi: 0x86}, + // Block 0x29, offset 0x2a + {value: 0x0000, lo: 0x05}, + {value: 0xa000, lo: 0xa5, hi: 0xa5}, + {value: 0x193c, lo: 0xa6, hi: 0xa6}, + {value: 0x9900, lo: 0xae, hi: 0xae}, + {value: 0x8102, lo: 0xb7, hi: 0xb7}, + {value: 0x8104, lo: 0xb9, hi: 0xba}, + // Block 0x2a, offset 0x2b + {value: 0x0000, lo: 0x01}, + {value: 0x812d, lo: 0x8d, hi: 0x8d}, + // Block 0x2b, offset 0x2c + {value: 0x0000, lo: 0x01}, + {value: 0xa000, lo: 0x80, hi: 0x92}, + // Block 0x2c, offset 0x2d + {value: 0x0000, lo: 0x01}, + {value: 0xb900, lo: 0xa1, hi: 0xb5}, + // Block 0x2d, offset 0x2e + {value: 0x0000, lo: 0x01}, + {value: 0x9900, lo: 0xa8, hi: 0xbf}, + // Block 0x2e, offset 0x2f + {value: 0x0000, lo: 0x01}, + {value: 0x9900, lo: 0x80, hi: 0x82}, + // Block 0x2f, offset 0x30 + {value: 0x0000, lo: 0x01}, + {value: 0x8132, lo: 0x9d, hi: 0x9f}, + // Block 0x30, offset 0x31 + {value: 0x0000, lo: 0x02}, + {value: 0x8104, lo: 0x94, hi: 0x94}, + {value: 0x8104, lo: 0xb4, hi: 0xb4}, + // Block 0x31, offset 0x32 + {value: 0x0000, lo: 0x02}, + {value: 0x8104, lo: 0x92, hi: 0x92}, + {value: 0x8132, lo: 0x9d, hi: 0x9d}, + // Block 0x32, offset 0x33 + {value: 0x0000, lo: 0x01}, + {value: 0x8131, lo: 0xa9, hi: 0xa9}, + // Block 0x33, offset 0x34 + {value: 0x0004, lo: 0x02}, + {value: 0x812e, lo: 0xb9, hi: 0xba}, + {value: 0x812d, lo: 0xbb, hi: 0xbb}, + // Block 0x34, offset 0x35 + {value: 0x0000, lo: 0x02}, + {value: 0x8132, lo: 0x97, hi: 0x97}, + {value: 0x812d, lo: 0x98, hi: 0x98}, + // Block 0x35, offset 0x36 + {value: 0x0000, lo: 0x03}, + {value: 0x8104, lo: 0xa0, hi: 0xa0}, + {value: 0x8132, lo: 0xb5, hi: 0xbc}, + {value: 0x812d, lo: 0xbf, hi: 0xbf}, + // Block 0x36, offset 0x37 + {value: 0x0000, lo: 0x08}, + {value: 0x197b, lo: 0x80, hi: 0x80}, + {value: 0x1982, lo: 0x81, hi: 0x81}, + {value: 0xa000, lo: 0x82, hi: 0x82}, + {value: 0x1989, lo: 0x83, hi: 0x83}, + {value: 0x8104, lo: 0x84, hi: 0x84}, + {value: 0x8132, lo: 0xab, hi: 0xab}, + {value: 0x812d, lo: 0xac, hi: 0xac}, + {value: 0x8132, lo: 0xad, hi: 0xb3}, + // Block 0x37, offset 0x38 + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0xaa, hi: 0xab}, + // Block 0x38, offset 0x39 + {value: 0x0000, lo: 0x02}, + {value: 0x8102, lo: 0xa6, hi: 0xa6}, + {value: 0x8104, lo: 0xb2, hi: 0xb3}, + // Block 0x39, offset 0x3a + {value: 0x0000, lo: 0x01}, + {value: 0x8102, lo: 0xb7, hi: 0xb7}, + // Block 0x3a, offset 0x3b + {value: 0x0000, lo: 0x09}, + {value: 0x8132, lo: 0x90, hi: 0x92}, + {value: 0x8101, lo: 0x94, hi: 0x94}, + {value: 0x812d, lo: 0x95, hi: 0x99}, + {value: 0x8132, lo: 0x9a, hi: 0x9b}, + {value: 0x812d, lo: 0x9c, hi: 0x9f}, + {value: 0x8132, lo: 0xa0, hi: 0xa0}, + {value: 0x8101, lo: 0xa2, hi: 0xa8}, + {value: 0x812d, lo: 0xad, hi: 0xad}, + {value: 0x8132, lo: 0xb4, hi: 0xb4}, + // Block 0x3b, offset 0x3c + {value: 0x0000, lo: 0x0e}, + {value: 0x8132, lo: 0x80, hi: 0x81}, + {value: 0x812d, lo: 0x82, hi: 0x82}, + {value: 0x8132, lo: 0x83, hi: 0x89}, + {value: 0x812d, lo: 0x8a, hi: 0x8a}, + {value: 0x8132, lo: 0x8b, hi: 0x8c}, + {value: 0x8135, lo: 0x8d, hi: 0x8d}, + {value: 0x812a, lo: 0x8e, hi: 0x8e}, + {value: 0x812d, lo: 0x8f, hi: 0x8f}, + {value: 0x8129, lo: 0x90, hi: 0x90}, + {value: 0x8132, lo: 0x91, hi: 0xa6}, + {value: 0x8134, lo: 0xbc, hi: 0xbc}, + {value: 0x812d, lo: 0xbd, hi: 0xbd}, + {value: 0x8132, lo: 0xbe, hi: 0xbe}, + {value: 0x812d, lo: 0xbf, hi: 0xbf}, + // Block 0x3c, offset 0x3d + {value: 0x0004, lo: 0x03}, + {value: 0x04a2, lo: 0x80, hi: 0x81}, + {value: 0x8100, lo: 0x97, hi: 0x97}, + {value: 0x8100, lo: 0xbe, hi: 0xbe}, + // Block 0x3d, offset 0x3e + {value: 0x0000, lo: 0x0d}, + {value: 0x8132, lo: 0x90, hi: 0x91}, + {value: 0x8101, lo: 0x92, hi: 0x93}, + {value: 0x8132, lo: 0x94, hi: 0x97}, + {value: 0x8101, lo: 0x98, hi: 0x9a}, + {value: 0x8132, lo: 0x9b, hi: 0x9c}, + {value: 0x8132, lo: 0xa1, hi: 0xa1}, + {value: 0x8101, lo: 0xa5, hi: 0xa6}, + {value: 0x8132, lo: 0xa7, hi: 0xa7}, + {value: 0x812d, lo: 0xa8, hi: 0xa8}, + {value: 0x8132, lo: 0xa9, hi: 0xa9}, + {value: 0x8101, lo: 0xaa, hi: 0xab}, + {value: 0x812d, lo: 0xac, hi: 0xaf}, + {value: 0x8132, lo: 0xb0, hi: 0xb0}, + // Block 0x3e, offset 0x3f + {value: 0x4262, lo: 0x02}, + {value: 0x01b5, lo: 0xa6, hi: 0xa6}, + {value: 0x0057, lo: 0xaa, hi: 0xab}, + // Block 0x3f, offset 0x40 + {value: 0x0007, lo: 0x05}, + {value: 0xa000, lo: 0x90, hi: 0x90}, + {value: 0xa000, lo: 0x92, hi: 0x92}, + {value: 0xa000, lo: 0x94, hi: 0x94}, + {value: 0x3ba0, lo: 0x9a, hi: 0x9b}, + {value: 0x3bae, lo: 0xae, hi: 0xae}, + // Block 0x40, offset 0x41 + {value: 0x000e, lo: 0x05}, + {value: 0x3bb5, lo: 0x8d, hi: 0x8e}, + {value: 0x3bbc, lo: 0x8f, hi: 0x8f}, + {value: 0xa000, lo: 0x90, hi: 0x90}, + {value: 0xa000, lo: 0x92, hi: 0x92}, + {value: 0xa000, lo: 0x94, hi: 0x94}, + // Block 0x41, offset 0x42 + {value: 0x6421, lo: 0x0a}, + {value: 0xa000, lo: 0x83, hi: 0x83}, + {value: 0x3bca, lo: 0x84, hi: 0x84}, + {value: 0xa000, lo: 0x88, hi: 0x88}, + {value: 0x3bd1, lo: 0x89, hi: 0x89}, + {value: 0xa000, lo: 0x8b, hi: 0x8b}, + {value: 0x3bd8, lo: 0x8c, hi: 0x8c}, + {value: 0xa000, lo: 0xa3, hi: 0xa3}, + {value: 0x3bdf, lo: 0xa4, hi: 0xa5}, + {value: 0x3be6, lo: 0xa6, hi: 0xa6}, + {value: 0xa000, lo: 0xbc, hi: 0xbc}, + // Block 0x42, offset 0x43 + {value: 0x0007, lo: 0x03}, + {value: 0x3c4f, lo: 0xa0, hi: 0xa1}, + {value: 0x3c79, lo: 0xa2, hi: 0xa3}, + {value: 0x3ca3, lo: 0xaa, hi: 0xad}, + // Block 0x43, offset 0x44 + {value: 0x0004, lo: 0x01}, + {value: 0x04fa, lo: 0xa9, hi: 0xaa}, + // Block 0x44, offset 0x45 + {value: 0x0000, lo: 0x01}, + {value: 0x44c4, lo: 0x9c, hi: 0x9c}, + // Block 0x45, offset 0x46 + {value: 0x0000, lo: 0x01}, + {value: 0x8132, lo: 0xaf, hi: 0xb1}, + // Block 0x46, offset 0x47 + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0xbf, hi: 0xbf}, + // Block 0x47, offset 0x48 + {value: 0x0000, lo: 0x01}, + {value: 0x8132, lo: 0xa0, hi: 0xbf}, + // Block 0x48, offset 0x49 + {value: 0x0000, lo: 0x05}, + {value: 0x812c, lo: 0xaa, hi: 0xaa}, + {value: 0x8131, lo: 0xab, hi: 0xab}, + {value: 0x8133, lo: 0xac, hi: 0xac}, + {value: 0x812e, lo: 0xad, hi: 0xad}, + {value: 0x812f, lo: 0xae, hi: 0xaf}, + // Block 0x49, offset 0x4a + {value: 0x0000, lo: 0x07}, + {value: 0x8100, lo: 0x84, hi: 0x84}, + {value: 0x8100, lo: 0x87, hi: 0x87}, + {value: 0x8100, lo: 0x90, hi: 0x90}, + {value: 0x8100, lo: 0x9e, hi: 0x9e}, + {value: 0x8100, lo: 0xa1, hi: 0xa1}, + {value: 0x8100, lo: 0xb2, hi: 0xb2}, + {value: 0x8100, lo: 0xbb, hi: 0xbb}, + // Block 0x4a, offset 0x4b + {value: 0x0000, lo: 0x03}, + {value: 0x8100, lo: 0x80, hi: 0x80}, + {value: 0x8100, lo: 0x8b, hi: 0x8b}, + {value: 0x8100, lo: 0x8e, hi: 0x8e}, + // Block 0x4b, offset 0x4c + {value: 0x0000, lo: 0x02}, + {value: 0x8132, lo: 0xaf, hi: 0xaf}, + {value: 0x8132, lo: 0xb4, hi: 0xbd}, + // Block 0x4c, offset 0x4d + {value: 0x0000, lo: 0x01}, + {value: 0x8132, lo: 0x9f, hi: 0x9f}, + // Block 0x4d, offset 0x4e + {value: 0x0000, lo: 0x01}, + {value: 0x8132, lo: 0xb0, hi: 0xb1}, + // Block 0x4e, offset 0x4f + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0x86, hi: 0x86}, + // Block 0x4f, offset 0x50 + {value: 0x0000, lo: 0x02}, + {value: 0x8104, lo: 0x84, hi: 0x84}, + {value: 0x8132, lo: 0xa0, hi: 0xb1}, + // Block 0x50, offset 0x51 + {value: 0x0000, lo: 0x01}, + {value: 0x812d, lo: 0xab, hi: 0xad}, + // Block 0x51, offset 0x52 + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0x93, hi: 0x93}, + // Block 0x52, offset 0x53 + {value: 0x0000, lo: 0x01}, + {value: 0x8102, lo: 0xb3, hi: 0xb3}, + // Block 0x53, offset 0x54 + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0x80, hi: 0x80}, + // Block 0x54, offset 0x55 + {value: 0x0000, lo: 0x05}, + {value: 0x8132, lo: 0xb0, hi: 0xb0}, + {value: 0x8132, lo: 0xb2, hi: 0xb3}, + {value: 0x812d, lo: 0xb4, hi: 0xb4}, + {value: 0x8132, lo: 0xb7, hi: 0xb8}, + {value: 0x8132, lo: 0xbe, hi: 0xbf}, + // Block 0x55, offset 0x56 + {value: 0x0000, lo: 0x02}, + {value: 0x8132, lo: 0x81, hi: 0x81}, + {value: 0x8104, lo: 0xb6, hi: 0xb6}, + // Block 0x56, offset 0x57 + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0xad, hi: 0xad}, + // Block 0x57, offset 0x58 + {value: 0x0000, lo: 0x06}, + {value: 0xe500, lo: 0x80, hi: 0x80}, + {value: 0xc600, lo: 0x81, hi: 0x9b}, + {value: 0xe500, lo: 0x9c, hi: 0x9c}, + {value: 0xc600, lo: 0x9d, hi: 0xb7}, + {value: 0xe500, lo: 0xb8, hi: 0xb8}, + {value: 0xc600, lo: 0xb9, hi: 0xbf}, + // Block 0x58, offset 0x59 + {value: 0x0000, lo: 0x05}, + {value: 0xc600, lo: 0x80, hi: 0x93}, + {value: 0xe500, lo: 0x94, hi: 0x94}, + {value: 0xc600, lo: 0x95, hi: 0xaf}, + {value: 0xe500, lo: 0xb0, hi: 0xb0}, + {value: 0xc600, lo: 0xb1, hi: 0xbf}, + // Block 0x59, offset 0x5a + {value: 0x0000, lo: 0x05}, + {value: 0xc600, lo: 0x80, hi: 0x8b}, + {value: 0xe500, lo: 0x8c, hi: 0x8c}, + {value: 0xc600, lo: 0x8d, hi: 0xa7}, + {value: 0xe500, lo: 0xa8, hi: 0xa8}, + {value: 0xc600, lo: 0xa9, hi: 0xbf}, + // Block 0x5a, offset 0x5b + {value: 0x0000, lo: 0x07}, + {value: 0xc600, lo: 0x80, hi: 0x83}, + {value: 0xe500, lo: 0x84, hi: 0x84}, + {value: 0xc600, lo: 0x85, hi: 0x9f}, + {value: 0xe500, lo: 0xa0, hi: 0xa0}, + {value: 0xc600, lo: 0xa1, hi: 0xbb}, + {value: 0xe500, lo: 0xbc, hi: 0xbc}, + {value: 0xc600, lo: 0xbd, hi: 0xbf}, + // Block 0x5b, offset 0x5c + {value: 0x0000, lo: 0x05}, + {value: 0xc600, lo: 0x80, hi: 0x97}, + {value: 0xe500, lo: 0x98, hi: 0x98}, + {value: 0xc600, lo: 0x99, hi: 0xb3}, + {value: 0xe500, lo: 0xb4, hi: 0xb4}, + {value: 0xc600, lo: 0xb5, hi: 0xbf}, + // Block 0x5c, offset 0x5d + {value: 0x0000, lo: 0x05}, + {value: 0xc600, lo: 0x80, hi: 0x8f}, + {value: 0xe500, lo: 0x90, hi: 0x90}, + {value: 0xc600, lo: 0x91, hi: 0xab}, + {value: 0xe500, lo: 0xac, hi: 0xac}, + {value: 0xc600, lo: 0xad, hi: 0xbf}, + // Block 0x5d, offset 0x5e + {value: 0x0000, lo: 0x05}, + {value: 0xc600, lo: 0x80, hi: 0x87}, + {value: 0xe500, lo: 0x88, hi: 0x88}, + {value: 0xc600, lo: 0x89, hi: 0xa3}, + {value: 0xe500, lo: 0xa4, hi: 0xa4}, + {value: 0xc600, lo: 0xa5, hi: 0xbf}, + // Block 0x5e, offset 0x5f + {value: 0x0000, lo: 0x03}, + {value: 0xc600, lo: 0x80, hi: 0x87}, + {value: 0xe500, lo: 0x88, hi: 0x88}, + {value: 0xc600, lo: 0x89, hi: 0xa3}, + // Block 0x5f, offset 0x60 + {value: 0x0006, lo: 0x0d}, + {value: 0x4377, lo: 0x9d, hi: 0x9d}, + {value: 0x8115, lo: 0x9e, hi: 0x9e}, + {value: 0x43e9, lo: 0x9f, hi: 0x9f}, + {value: 0x43d7, lo: 0xaa, hi: 0xab}, + {value: 0x44db, lo: 0xac, hi: 0xac}, + {value: 0x44e3, lo: 0xad, hi: 0xad}, + {value: 0x432f, lo: 0xae, hi: 0xb1}, + {value: 0x434d, lo: 0xb2, hi: 0xb4}, + {value: 0x4365, lo: 0xb5, hi: 0xb6}, + {value: 0x4371, lo: 0xb8, hi: 0xb8}, + {value: 0x437d, lo: 0xb9, hi: 0xbb}, + {value: 0x4395, lo: 0xbc, hi: 0xbc}, + {value: 0x439b, lo: 0xbe, hi: 0xbe}, + // Block 0x60, offset 0x61 + {value: 0x0006, lo: 0x08}, + {value: 0x43a1, lo: 0x80, hi: 0x81}, + {value: 0x43ad, lo: 0x83, hi: 0x84}, + {value: 0x43bf, lo: 0x86, hi: 0x89}, + {value: 0x43e3, lo: 0x8a, hi: 0x8a}, + {value: 0x435f, lo: 0x8b, hi: 0x8b}, + {value: 0x4347, lo: 0x8c, hi: 0x8c}, + {value: 0x438f, lo: 0x8d, hi: 0x8d}, + {value: 0x43b9, lo: 0x8e, hi: 0x8e}, + // Block 0x61, offset 0x62 + {value: 0x0000, lo: 0x02}, + {value: 0x8100, lo: 0xa4, hi: 0xa5}, + {value: 0x8100, lo: 0xb0, hi: 0xb1}, + // Block 0x62, offset 0x63 + {value: 0x0000, lo: 0x02}, + {value: 0x8100, lo: 0x9b, hi: 0x9d}, + {value: 0x8200, lo: 0x9e, hi: 0xa3}, + // Block 0x63, offset 0x64 + {value: 0x0000, lo: 0x01}, + {value: 0x8100, lo: 0x90, hi: 0x90}, + // Block 0x64, offset 0x65 + {value: 0x0000, lo: 0x02}, + {value: 0x8100, lo: 0x99, hi: 0x99}, + {value: 0x8200, lo: 0xb2, hi: 0xb4}, + // Block 0x65, offset 0x66 + {value: 0x0000, lo: 0x01}, + {value: 0x8100, lo: 0xbc, hi: 0xbd}, + // Block 0x66, offset 0x67 + {value: 0x0000, lo: 0x01}, + {value: 0x8132, lo: 0xa0, hi: 0xa6}, + // Block 0x67, offset 0x68 + {value: 0x0000, lo: 0x04}, + {value: 0x8100, lo: 0x89, hi: 0x8c}, + {value: 0x8100, lo: 0xb0, hi: 0xb2}, + {value: 0x8100, lo: 0xb4, hi: 0xb4}, + {value: 0x8100, lo: 0xb6, hi: 0xbf}, + // Block 0x68, offset 0x69 + {value: 0x0000, lo: 0x01}, + {value: 0x8100, lo: 0x81, hi: 0x8c}, + // Block 0x69, offset 0x6a + {value: 0x0000, lo: 0x01}, + {value: 0x8100, lo: 0xb5, hi: 0xba}, + // Block 0x6a, offset 0x6b + {value: 0x0000, lo: 0x01}, + {value: 0x49d2, lo: 0x9e, hi: 0x9f}, + // Block 0x6b, offset 0x6c + {value: 0x0000, lo: 0x01}, + {value: 0x8100, lo: 0xa3, hi: 0xa3}, + // Block 0x6c, offset 0x6d + {value: 0x0000, lo: 0x01}, + {value: 0x812d, lo: 0xbd, hi: 0xbd}, + // Block 0x6d, offset 0x6e + {value: 0x002c, lo: 0x05}, + {value: 0x812d, lo: 0x8d, hi: 0x8d}, + {value: 0x8132, lo: 0x8f, hi: 0x8f}, + {value: 0x8132, lo: 0xb8, hi: 0xb8}, + {value: 0x8101, lo: 0xb9, hi: 0xba}, + {value: 0x8104, lo: 0xbf, hi: 0xbf}, + // Block 0x6e, offset 0x6f + {value: 0x17fe, lo: 0x07}, + {value: 0xa000, lo: 0x99, hi: 0x99}, + {value: 0x421f, lo: 0x9a, hi: 0x9a}, + {value: 0xa000, lo: 0x9b, hi: 0x9b}, + {value: 0x4229, lo: 0x9c, hi: 0x9c}, + {value: 0xa000, lo: 0xa5, hi: 0xa5}, + {value: 0x4233, lo: 0xab, hi: 0xab}, + {value: 0x8104, lo: 0xb9, hi: 0xba}, + // Block 0x6f, offset 0x70 + {value: 0x0000, lo: 0x06}, + {value: 0x8132, lo: 0x80, hi: 0x82}, + {value: 0x9900, lo: 0xa7, hi: 0xa7}, + {value: 0x1990, lo: 0xae, hi: 0xae}, + {value: 0x1999, lo: 0xaf, hi: 0xaf}, + {value: 0xa000, lo: 0xb1, hi: 0xb2}, + {value: 0x8104, lo: 0xb3, hi: 0xb4}, + // Block 0x70, offset 0x71 + {value: 0x0000, lo: 0x02}, + {value: 0x8104, lo: 0xb6, hi: 0xb6}, + {value: 0x8102, lo: 0xb7, hi: 0xb7}, + // Block 0x71, offset 0x72 + {value: 0x0000, lo: 0x0c}, + {value: 0x45b3, lo: 0x9e, hi: 0x9e}, + {value: 0x45bd, lo: 0x9f, hi: 0x9f}, + {value: 0x45f1, lo: 0xa0, hi: 0xa0}, + {value: 0x45ff, lo: 0xa1, hi: 0xa1}, + {value: 0x460d, lo: 0xa2, hi: 0xa2}, + {value: 0x461b, lo: 0xa3, hi: 0xa3}, + {value: 0x4629, lo: 0xa4, hi: 0xa4}, + {value: 0x812b, lo: 0xa5, hi: 0xa6}, + {value: 0x8101, lo: 0xa7, hi: 0xa9}, + {value: 0x8130, lo: 0xad, hi: 0xad}, + {value: 0x812b, lo: 0xae, hi: 0xb2}, + {value: 0x812d, lo: 0xbb, hi: 0xbf}, + // Block 0x72, offset 0x73 + {value: 0x0000, lo: 0x09}, + {value: 0x812d, lo: 0x80, hi: 0x82}, + {value: 0x8132, lo: 0x85, hi: 0x89}, + {value: 0x812d, lo: 0x8a, hi: 0x8b}, + {value: 0x8132, lo: 0xaa, hi: 0xad}, + {value: 0x45c7, lo: 0xbb, hi: 0xbb}, + {value: 0x45d1, lo: 0xbc, hi: 0xbc}, + {value: 0x4637, lo: 0xbd, hi: 0xbd}, + {value: 0x4653, lo: 0xbe, hi: 0xbe}, + {value: 0x4645, lo: 0xbf, hi: 0xbf}, + // Block 0x73, offset 0x74 + {value: 0x0000, lo: 0x01}, + {value: 0x4661, lo: 0x80, hi: 0x80}, + // Block 0x74, offset 0x75 + {value: 0x0000, lo: 0x01}, + {value: 0x8132, lo: 0x82, hi: 0x84}, + // Block 0x75, offset 0x76 + {value: 0x0000, lo: 0x01}, + {value: 0x8100, lo: 0x93, hi: 0x93}, +} + +// nfcLookup: 1216 bytes +// Block 0 is the null block. +var nfcLookup = [1216]uint8{ + // Block 0x0, offset 0x0 + // Block 0x1, offset 0x40 + // Block 0x2, offset 0x80 + // Block 0x3, offset 0xc0 + 0x0c2: 0x2c, 0x0c3: 0x01, 0x0c4: 0x02, 0x0c5: 0x03, 0x0c6: 0x2d, 0x0c7: 0x04, + 0x0c8: 0x05, 0x0ca: 0x2e, 0x0cb: 0x2f, 0x0cc: 0x06, 0x0cd: 0x07, 0x0ce: 0x08, 0x0cf: 0x30, + 0x0d0: 0x09, 0x0d1: 0x31, 0x0d2: 0x32, 0x0d3: 0x0a, 0x0d6: 0x0b, 0x0d7: 0x33, + 0x0d8: 0x34, 0x0d9: 0x0c, 0x0db: 0x35, 0x0dc: 0x36, 0x0dd: 0x37, 0x0df: 0x38, + 0x0e0: 0x02, 0x0e1: 0x03, 0x0e2: 0x04, 0x0e3: 0x05, + 0x0ea: 0x06, 0x0eb: 0x07, 0x0ec: 0x08, 0x0ed: 0x09, 0x0ef: 0x0a, + 0x0f0: 0x10, + // Block 0x4, offset 0x100 + 0x120: 0x39, 0x121: 0x3a, 0x123: 0x3b, 0x124: 0x3c, 0x125: 0x3d, 0x126: 0x3e, 0x127: 0x3f, + 0x128: 0x40, 0x129: 0x41, 0x12a: 0x42, 0x12b: 0x43, 0x12c: 0x3e, 0x12d: 0x44, 0x12e: 0x45, 0x12f: 0x46, + 0x131: 0x47, 0x132: 0x48, 0x133: 0x49, 0x134: 0x4a, 0x135: 0x4b, 0x137: 0x4c, + 0x138: 0x4d, 0x139: 0x4e, 0x13a: 0x4f, 0x13b: 0x50, 0x13c: 0x51, 0x13d: 0x52, 0x13e: 0x53, 0x13f: 0x54, + // Block 0x5, offset 0x140 + 0x140: 0x55, 0x142: 0x56, 0x144: 0x57, 0x145: 0x58, 0x146: 0x59, 0x147: 0x5a, + 0x14d: 0x5b, + 0x15c: 0x5c, 0x15f: 0x5d, + 0x162: 0x5e, 0x164: 0x5f, + 0x168: 0x60, 0x169: 0x61, 0x16c: 0x0d, 0x16d: 0x62, 0x16e: 0x63, 0x16f: 0x64, + 0x170: 0x65, 0x173: 0x66, 0x177: 0x67, + 0x178: 0x0e, 0x179: 0x0f, 0x17a: 0x10, 0x17b: 0x11, 0x17c: 0x12, 0x17d: 0x13, 0x17e: 0x14, 0x17f: 0x15, + // Block 0x6, offset 0x180 + 0x180: 0x68, 0x183: 0x69, 0x184: 0x6a, 0x186: 0x6b, 0x187: 0x6c, + 0x188: 0x6d, 0x189: 0x16, 0x18a: 0x17, 0x18b: 0x6e, 0x18c: 0x6f, + 0x1ab: 0x70, + 0x1b3: 0x71, 0x1b5: 0x72, 0x1b7: 0x73, + // Block 0x7, offset 0x1c0 + 0x1c0: 0x74, 0x1c1: 0x18, 0x1c2: 0x19, 0x1c3: 0x1a, + 0x1cc: 0x75, 0x1cd: 0x76, + // Block 0x8, offset 0x200 + 0x219: 0x77, 0x21a: 0x78, 0x21b: 0x79, + 0x220: 0x7a, 0x223: 0x7b, 0x224: 0x7c, 0x225: 0x7d, 0x226: 0x7e, 0x227: 0x7f, + 0x22a: 0x80, 0x22b: 0x81, 0x22f: 0x82, + 0x230: 0x83, 0x231: 0x84, 0x232: 0x85, 0x233: 0x86, 0x234: 0x87, 0x235: 0x88, 0x236: 0x89, 0x237: 0x83, + 0x238: 0x84, 0x239: 0x85, 0x23a: 0x86, 0x23b: 0x87, 0x23c: 0x88, 0x23d: 0x89, 0x23e: 0x83, 0x23f: 0x84, + // Block 0x9, offset 0x240 + 0x240: 0x85, 0x241: 0x86, 0x242: 0x87, 0x243: 0x88, 0x244: 0x89, 0x245: 0x83, 0x246: 0x84, 0x247: 0x85, + 0x248: 0x86, 0x249: 0x87, 0x24a: 0x88, 0x24b: 0x89, 0x24c: 0x83, 0x24d: 0x84, 0x24e: 0x85, 0x24f: 0x86, + 0x250: 0x87, 0x251: 0x88, 0x252: 0x89, 0x253: 0x83, 0x254: 0x84, 0x255: 0x85, 0x256: 0x86, 0x257: 0x87, + 0x258: 0x88, 0x259: 0x89, 0x25a: 0x83, 0x25b: 0x84, 0x25c: 0x85, 0x25d: 0x86, 0x25e: 0x87, 0x25f: 0x88, + 0x260: 0x89, 0x261: 0x83, 0x262: 0x84, 0x263: 0x85, 0x264: 0x86, 0x265: 0x87, 0x266: 0x88, 0x267: 0x89, + 0x268: 0x83, 0x269: 0x84, 0x26a: 0x85, 0x26b: 0x86, 0x26c: 0x87, 0x26d: 0x88, 0x26e: 0x89, 0x26f: 0x83, + 0x270: 0x84, 0x271: 0x85, 0x272: 0x86, 0x273: 0x87, 0x274: 0x88, 0x275: 0x89, 0x276: 0x83, 0x277: 0x84, + 0x278: 0x85, 0x279: 0x86, 0x27a: 0x87, 0x27b: 0x88, 0x27c: 0x89, 0x27d: 0x83, 0x27e: 0x84, 0x27f: 0x85, + // Block 0xa, offset 0x280 + 0x280: 0x86, 0x281: 0x87, 0x282: 0x88, 0x283: 0x89, 0x284: 0x83, 0x285: 0x84, 0x286: 0x85, 0x287: 0x86, + 0x288: 0x87, 0x289: 0x88, 0x28a: 0x89, 0x28b: 0x83, 0x28c: 0x84, 0x28d: 0x85, 0x28e: 0x86, 0x28f: 0x87, + 0x290: 0x88, 0x291: 0x89, 0x292: 0x83, 0x293: 0x84, 0x294: 0x85, 0x295: 0x86, 0x296: 0x87, 0x297: 0x88, + 0x298: 0x89, 0x299: 0x83, 0x29a: 0x84, 0x29b: 0x85, 0x29c: 0x86, 0x29d: 0x87, 0x29e: 0x88, 0x29f: 0x89, + 0x2a0: 0x83, 0x2a1: 0x84, 0x2a2: 0x85, 0x2a3: 0x86, 0x2a4: 0x87, 0x2a5: 0x88, 0x2a6: 0x89, 0x2a7: 0x83, + 0x2a8: 0x84, 0x2a9: 0x85, 0x2aa: 0x86, 0x2ab: 0x87, 0x2ac: 0x88, 0x2ad: 0x89, 0x2ae: 0x83, 0x2af: 0x84, + 0x2b0: 0x85, 0x2b1: 0x86, 0x2b2: 0x87, 0x2b3: 0x88, 0x2b4: 0x89, 0x2b5: 0x83, 0x2b6: 0x84, 0x2b7: 0x85, + 0x2b8: 0x86, 0x2b9: 0x87, 0x2ba: 0x88, 0x2bb: 0x89, 0x2bc: 0x83, 0x2bd: 0x84, 0x2be: 0x85, 0x2bf: 0x86, + // Block 0xb, offset 0x2c0 + 0x2c0: 0x87, 0x2c1: 0x88, 0x2c2: 0x89, 0x2c3: 0x83, 0x2c4: 0x84, 0x2c5: 0x85, 0x2c6: 0x86, 0x2c7: 0x87, + 0x2c8: 0x88, 0x2c9: 0x89, 0x2ca: 0x83, 0x2cb: 0x84, 0x2cc: 0x85, 0x2cd: 0x86, 0x2ce: 0x87, 0x2cf: 0x88, + 0x2d0: 0x89, 0x2d1: 0x83, 0x2d2: 0x84, 0x2d3: 0x85, 0x2d4: 0x86, 0x2d5: 0x87, 0x2d6: 0x88, 0x2d7: 0x89, + 0x2d8: 0x83, 0x2d9: 0x84, 0x2da: 0x85, 0x2db: 0x86, 0x2dc: 0x87, 0x2dd: 0x88, 0x2de: 0x8a, + // Block 0xc, offset 0x300 + 0x324: 0x1b, 0x325: 0x1c, 0x326: 0x1d, 0x327: 0x1e, + 0x328: 0x1f, 0x329: 0x20, 0x32a: 0x21, 0x32b: 0x22, 0x32c: 0x8b, 0x32d: 0x8c, 0x32e: 0x8d, + 0x331: 0x8e, 0x332: 0x8f, 0x333: 0x90, 0x334: 0x91, + 0x338: 0x92, 0x339: 0x93, 0x33a: 0x94, 0x33b: 0x95, 0x33e: 0x96, 0x33f: 0x97, + // Block 0xd, offset 0x340 + 0x347: 0x98, + 0x368: 0x99, + // Block 0xe, offset 0x380 + 0x381: 0x7a, 0x382: 0x9a, 0x384: 0x9b, 0x387: 0x7f, + 0x39a: 0x9c, + // Block 0xf, offset 0x3c0 + 0x3c5: 0x9d, 0x3c6: 0x9e, 0x3c7: 0x9f, + 0x3c9: 0xa0, + // Block 0x10, offset 0x400 + 0x408: 0xa1, + // Block 0x11, offset 0x440 + 0x460: 0x23, 0x461: 0x24, 0x462: 0x25, 0x463: 0x26, 0x464: 0x27, 0x465: 0x28, 0x466: 0x29, 0x467: 0x2a, + 0x468: 0x2b, + // Block 0x12, offset 0x480 + 0x490: 0x0b, 0x491: 0x0c, + 0x49d: 0x0d, 0x49f: 0x0e, + 0x4af: 0x0f, +} + +var nfcTrie = trie{nfcLookup[:], nfcValues[:], nfcSparseValues[:], nfcSparseOffset[:], 44} + +// nfkcValues: 5760 entries, 11520 bytes +// Block 2 is the null block. +var nfkcValues = [5760]uint16{ + // Block 0x0, offset 0x0 + 0x003c: 0xa000, 0x003d: 0xa000, 0x003e: 0xa000, + // Block 0x1, offset 0x40 + 0x0041: 0xa000, 0x0042: 0xa000, 0x0043: 0xa000, 0x0044: 0xa000, 0x0045: 0xa000, + 0x0046: 0xa000, 0x0047: 0xa000, 0x0048: 0xa000, 0x0049: 0xa000, 0x004a: 0xa000, 0x004b: 0xa000, + 0x004c: 0xa000, 0x004d: 0xa000, 0x004e: 0xa000, 0x004f: 0xa000, 0x0050: 0xa000, + 0x0052: 0xa000, 0x0053: 0xa000, 0x0054: 0xa000, 0x0055: 0xa000, 0x0056: 0xa000, 0x0057: 0xa000, + 0x0058: 0xa000, 0x0059: 0xa000, 0x005a: 0xa000, + 0x0061: 0xa000, 0x0062: 0xa000, 0x0063: 0xa000, + 0x0064: 0xa000, 0x0065: 0xa000, 0x0066: 0xa000, 0x0067: 0xa000, 0x0068: 0xa000, 0x0069: 0xa000, + 0x006a: 0xa000, 0x006b: 0xa000, 0x006c: 0xa000, 0x006d: 0xa000, 0x006e: 0xa000, 0x006f: 0xa000, + 0x0070: 0xa000, 0x0072: 0xa000, 0x0073: 0xa000, 0x0074: 0xa000, 0x0075: 0xa000, + 0x0076: 0xa000, 0x0077: 0xa000, 0x0078: 0xa000, 0x0079: 0xa000, 0x007a: 0xa000, + // Block 0x2, offset 0x80 + // Block 0x3, offset 0xc0 + 0x00c0: 0x2f56, 0x00c1: 0x2f5b, 0x00c2: 0x466f, 0x00c3: 0x2f60, 0x00c4: 0x467e, 0x00c5: 0x4683, + 0x00c6: 0xa000, 0x00c7: 0x468d, 0x00c8: 0x2fc9, 0x00c9: 0x2fce, 0x00ca: 0x4692, 0x00cb: 0x2fe2, + 0x00cc: 0x3055, 0x00cd: 0x305a, 0x00ce: 0x305f, 0x00cf: 0x46a6, 0x00d1: 0x30eb, + 0x00d2: 0x310e, 0x00d3: 0x3113, 0x00d4: 0x46b0, 0x00d5: 0x46b5, 0x00d6: 0x46c4, + 0x00d8: 0xa000, 0x00d9: 0x319a, 0x00da: 0x319f, 0x00db: 0x31a4, 0x00dc: 0x46f6, 0x00dd: 0x321c, + 0x00e0: 0x3262, 0x00e1: 0x3267, 0x00e2: 0x4700, 0x00e3: 0x326c, + 0x00e4: 0x470f, 0x00e5: 0x4714, 0x00e6: 0xa000, 0x00e7: 0x471e, 0x00e8: 0x32d5, 0x00e9: 0x32da, + 0x00ea: 0x4723, 0x00eb: 0x32ee, 0x00ec: 0x3366, 0x00ed: 0x336b, 0x00ee: 0x3370, 0x00ef: 0x4737, + 0x00f1: 0x33fc, 0x00f2: 0x341f, 0x00f3: 0x3424, 0x00f4: 0x4741, 0x00f5: 0x4746, + 0x00f6: 0x4755, 0x00f8: 0xa000, 0x00f9: 0x34b0, 0x00fa: 0x34b5, 0x00fb: 0x34ba, + 0x00fc: 0x4787, 0x00fd: 0x3537, 0x00ff: 0x3550, + // Block 0x4, offset 0x100 + 0x0100: 0x2f65, 0x0101: 0x3271, 0x0102: 0x4674, 0x0103: 0x4705, 0x0104: 0x2f83, 0x0105: 0x328f, + 0x0106: 0x2f97, 0x0107: 0x32a3, 0x0108: 0x2f9c, 0x0109: 0x32a8, 0x010a: 0x2fa1, 0x010b: 0x32ad, + 0x010c: 0x2fa6, 0x010d: 0x32b2, 0x010e: 0x2fb0, 0x010f: 0x32bc, + 0x0112: 0x4697, 0x0113: 0x4728, 0x0114: 0x2fd8, 0x0115: 0x32e4, 0x0116: 0x2fdd, 0x0117: 0x32e9, + 0x0118: 0x2ffb, 0x0119: 0x3307, 0x011a: 0x2fec, 0x011b: 0x32f8, 0x011c: 0x3014, 0x011d: 0x3320, + 0x011e: 0x301e, 0x011f: 0x332a, 0x0120: 0x3023, 0x0121: 0x332f, 0x0122: 0x302d, 0x0123: 0x3339, + 0x0124: 0x3032, 0x0125: 0x333e, 0x0128: 0x3064, 0x0129: 0x3375, + 0x012a: 0x3069, 0x012b: 0x337a, 0x012c: 0x306e, 0x012d: 0x337f, 0x012e: 0x3091, 0x012f: 0x339d, + 0x0130: 0x3073, 0x0132: 0x1a9c, 0x0133: 0x1b26, 0x0134: 0x309b, 0x0135: 0x33a7, + 0x0136: 0x30af, 0x0137: 0x33c0, 0x0139: 0x30b9, 0x013a: 0x33ca, 0x013b: 0x30c3, + 0x013c: 0x33d4, 0x013d: 0x30be, 0x013e: 0x33cf, 0x013f: 0x1ceb, + // Block 0x5, offset 0x140 + 0x0140: 0x1d73, 0x0143: 0x30e6, 0x0144: 0x33f7, 0x0145: 0x30ff, + 0x0146: 0x3410, 0x0147: 0x30f5, 0x0148: 0x3406, 0x0149: 0x1d9b, + 0x014c: 0x46ba, 0x014d: 0x474b, 0x014e: 0x3118, 0x014f: 0x3429, 0x0150: 0x3122, 0x0151: 0x3433, + 0x0154: 0x3140, 0x0155: 0x3451, 0x0156: 0x3159, 0x0157: 0x346a, + 0x0158: 0x314a, 0x0159: 0x345b, 0x015a: 0x46dd, 0x015b: 0x476e, 0x015c: 0x3163, 0x015d: 0x3474, + 0x015e: 0x3172, 0x015f: 0x3483, 0x0160: 0x46e2, 0x0161: 0x4773, 0x0162: 0x318b, 0x0163: 0x34a1, + 0x0164: 0x317c, 0x0165: 0x3492, 0x0168: 0x46ec, 0x0169: 0x477d, + 0x016a: 0x46f1, 0x016b: 0x4782, 0x016c: 0x31a9, 0x016d: 0x34bf, 0x016e: 0x31b3, 0x016f: 0x34c9, + 0x0170: 0x31b8, 0x0171: 0x34ce, 0x0172: 0x31d6, 0x0173: 0x34ec, 0x0174: 0x31f9, 0x0175: 0x350f, + 0x0176: 0x3221, 0x0177: 0x353c, 0x0178: 0x3235, 0x0179: 0x3244, 0x017a: 0x3564, 0x017b: 0x324e, + 0x017c: 0x356e, 0x017d: 0x3253, 0x017e: 0x3573, 0x017f: 0x00a7, + // Block 0x6, offset 0x180 + 0x0184: 0x2e7c, 0x0185: 0x2e82, + 0x0186: 0x2e88, 0x0187: 0x1ab1, 0x0188: 0x1ab4, 0x0189: 0x1b47, 0x018a: 0x1ac6, 0x018b: 0x1ac9, + 0x018c: 0x1b7d, 0x018d: 0x2f6f, 0x018e: 0x327b, 0x018f: 0x307d, 0x0190: 0x3389, 0x0191: 0x3127, + 0x0192: 0x3438, 0x0193: 0x31bd, 0x0194: 0x34d3, 0x0195: 0x39b6, 0x0196: 0x3b45, 0x0197: 0x39af, + 0x0198: 0x3b3e, 0x0199: 0x39bd, 0x019a: 0x3b4c, 0x019b: 0x39a8, 0x019c: 0x3b37, + 0x019e: 0x3897, 0x019f: 0x3a26, 0x01a0: 0x3890, 0x01a1: 0x3a1f, 0x01a2: 0x359a, 0x01a3: 0x35ac, + 0x01a6: 0x3028, 0x01a7: 0x3334, 0x01a8: 0x30a5, 0x01a9: 0x33b6, + 0x01aa: 0x46d3, 0x01ab: 0x4764, 0x01ac: 0x3977, 0x01ad: 0x3b06, 0x01ae: 0x35be, 0x01af: 0x35c4, + 0x01b0: 0x33ac, 0x01b1: 0x1a81, 0x01b2: 0x1a84, 0x01b3: 0x1b0e, 0x01b4: 0x300f, 0x01b5: 0x331b, + 0x01b8: 0x30e1, 0x01b9: 0x33f2, 0x01ba: 0x389e, 0x01bb: 0x3a2d, + 0x01bc: 0x3594, 0x01bd: 0x35a6, 0x01be: 0x35a0, 0x01bf: 0x35b2, + // Block 0x7, offset 0x1c0 + 0x01c0: 0x2f74, 0x01c1: 0x3280, 0x01c2: 0x2f79, 0x01c3: 0x3285, 0x01c4: 0x2ff1, 0x01c5: 0x32fd, + 0x01c6: 0x2ff6, 0x01c7: 0x3302, 0x01c8: 0x3082, 0x01c9: 0x338e, 0x01ca: 0x3087, 0x01cb: 0x3393, + 0x01cc: 0x312c, 0x01cd: 0x343d, 0x01ce: 0x3131, 0x01cf: 0x3442, 0x01d0: 0x314f, 0x01d1: 0x3460, + 0x01d2: 0x3154, 0x01d3: 0x3465, 0x01d4: 0x31c2, 0x01d5: 0x34d8, 0x01d6: 0x31c7, 0x01d7: 0x34dd, + 0x01d8: 0x316d, 0x01d9: 0x347e, 0x01da: 0x3186, 0x01db: 0x349c, + 0x01de: 0x3041, 0x01df: 0x334d, + 0x01e6: 0x4679, 0x01e7: 0x470a, 0x01e8: 0x46a1, 0x01e9: 0x4732, + 0x01ea: 0x3946, 0x01eb: 0x3ad5, 0x01ec: 0x3923, 0x01ed: 0x3ab2, 0x01ee: 0x46bf, 0x01ef: 0x4750, + 0x01f0: 0x393f, 0x01f1: 0x3ace, 0x01f2: 0x322b, 0x01f3: 0x3546, + // Block 0x8, offset 0x200 + 0x0200: 0x9932, 0x0201: 0x9932, 0x0202: 0x9932, 0x0203: 0x9932, 0x0204: 0x9932, 0x0205: 0x8132, + 0x0206: 0x9932, 0x0207: 0x9932, 0x0208: 0x9932, 0x0209: 0x9932, 0x020a: 0x9932, 0x020b: 0x9932, + 0x020c: 0x9932, 0x020d: 0x8132, 0x020e: 0x8132, 0x020f: 0x9932, 0x0210: 0x8132, 0x0211: 0x9932, + 0x0212: 0x8132, 0x0213: 0x9932, 0x0214: 0x9932, 0x0215: 0x8133, 0x0216: 0x812d, 0x0217: 0x812d, + 0x0218: 0x812d, 0x0219: 0x812d, 0x021a: 0x8133, 0x021b: 0x992b, 0x021c: 0x812d, 0x021d: 0x812d, + 0x021e: 0x812d, 0x021f: 0x812d, 0x0220: 0x812d, 0x0221: 0x8129, 0x0222: 0x8129, 0x0223: 0x992d, + 0x0224: 0x992d, 0x0225: 0x992d, 0x0226: 0x992d, 0x0227: 0x9929, 0x0228: 0x9929, 0x0229: 0x812d, + 0x022a: 0x812d, 0x022b: 0x812d, 0x022c: 0x812d, 0x022d: 0x992d, 0x022e: 0x992d, 0x022f: 0x812d, + 0x0230: 0x992d, 0x0231: 0x992d, 0x0232: 0x812d, 0x0233: 0x812d, 0x0234: 0x8101, 0x0235: 0x8101, + 0x0236: 0x8101, 0x0237: 0x8101, 0x0238: 0x9901, 0x0239: 0x812d, 0x023a: 0x812d, 0x023b: 0x812d, + 0x023c: 0x812d, 0x023d: 0x8132, 0x023e: 0x8132, 0x023f: 0x8132, + // Block 0x9, offset 0x240 + 0x0240: 0x4995, 0x0241: 0x499a, 0x0242: 0x9932, 0x0243: 0x499f, 0x0244: 0x49a4, 0x0245: 0x9936, + 0x0246: 0x8132, 0x0247: 0x812d, 0x0248: 0x812d, 0x0249: 0x812d, 0x024a: 0x8132, 0x024b: 0x8132, + 0x024c: 0x8132, 0x024d: 0x812d, 0x024e: 0x812d, 0x0250: 0x8132, 0x0251: 0x8132, + 0x0252: 0x8132, 0x0253: 0x812d, 0x0254: 0x812d, 0x0255: 0x812d, 0x0256: 0x812d, 0x0257: 0x8132, + 0x0258: 0x8133, 0x0259: 0x812d, 0x025a: 0x812d, 0x025b: 0x8132, 0x025c: 0x8134, 0x025d: 0x8135, + 0x025e: 0x8135, 0x025f: 0x8134, 0x0260: 0x8135, 0x0261: 0x8135, 0x0262: 0x8134, 0x0263: 0x8132, + 0x0264: 0x8132, 0x0265: 0x8132, 0x0266: 0x8132, 0x0267: 0x8132, 0x0268: 0x8132, 0x0269: 0x8132, + 0x026a: 0x8132, 0x026b: 0x8132, 0x026c: 0x8132, 0x026d: 0x8132, 0x026e: 0x8132, 0x026f: 0x8132, + 0x0274: 0x016d, + 0x027a: 0x428c, + 0x027e: 0x0037, + // Block 0xa, offset 0x280 + 0x0284: 0x4241, 0x0285: 0x4462, + 0x0286: 0x35d0, 0x0287: 0x00ce, 0x0288: 0x35ee, 0x0289: 0x35fa, 0x028a: 0x360c, + 0x028c: 0x362a, 0x028e: 0x363c, 0x028f: 0x365a, 0x0290: 0x3def, 0x0291: 0xa000, + 0x0295: 0xa000, 0x0297: 0xa000, + 0x0299: 0xa000, + 0x029f: 0xa000, 0x02a1: 0xa000, + 0x02a5: 0xa000, 0x02a9: 0xa000, + 0x02aa: 0x361e, 0x02ab: 0x364e, 0x02ac: 0x47e5, 0x02ad: 0x367e, 0x02ae: 0x480f, 0x02af: 0x3690, + 0x02b0: 0x3e57, 0x02b1: 0xa000, 0x02b5: 0xa000, + 0x02b7: 0xa000, 0x02b9: 0xa000, + 0x02bf: 0xa000, + // Block 0xb, offset 0x2c0 + 0x02c1: 0xa000, 0x02c5: 0xa000, + 0x02c9: 0xa000, 0x02ca: 0x4827, 0x02cb: 0x4845, + 0x02cc: 0x36ae, 0x02cd: 0x36c6, 0x02ce: 0x485d, 0x02d0: 0x01bb, 0x02d1: 0x01cd, + 0x02d2: 0x01a9, 0x02d3: 0x42f3, 0x02d4: 0x42f9, 0x02d5: 0x01f7, 0x02d6: 0x01e5, + 0x02f0: 0x01d3, 0x02f1: 0x01e8, 0x02f2: 0x01eb, 0x02f4: 0x0185, 0x02f5: 0x01c4, + 0x02f9: 0x01a3, + // Block 0xc, offset 0x300 + 0x0300: 0x3708, 0x0301: 0x3714, 0x0303: 0x3702, + 0x0306: 0xa000, 0x0307: 0x36f0, + 0x030c: 0x3744, 0x030d: 0x372c, 0x030e: 0x3756, 0x0310: 0xa000, + 0x0313: 0xa000, 0x0315: 0xa000, 0x0316: 0xa000, 0x0317: 0xa000, + 0x0318: 0xa000, 0x0319: 0x3738, 0x031a: 0xa000, + 0x031e: 0xa000, 0x0323: 0xa000, + 0x0327: 0xa000, + 0x032b: 0xa000, 0x032d: 0xa000, + 0x0330: 0xa000, 0x0333: 0xa000, 0x0335: 0xa000, + 0x0336: 0xa000, 0x0337: 0xa000, 0x0338: 0xa000, 0x0339: 0x37bc, 0x033a: 0xa000, + 0x033e: 0xa000, + // Block 0xd, offset 0x340 + 0x0341: 0x371a, 0x0342: 0x379e, + 0x0350: 0x36f6, 0x0351: 0x377a, + 0x0352: 0x36fc, 0x0353: 0x3780, 0x0356: 0x370e, 0x0357: 0x3792, + 0x0358: 0xa000, 0x0359: 0xa000, 0x035a: 0x3810, 0x035b: 0x3816, 0x035c: 0x3720, 0x035d: 0x37a4, + 0x035e: 0x3726, 0x035f: 0x37aa, 0x0362: 0x3732, 0x0363: 0x37b6, + 0x0364: 0x373e, 0x0365: 0x37c2, 0x0366: 0x374a, 0x0367: 0x37ce, 0x0368: 0xa000, 0x0369: 0xa000, + 0x036a: 0x381c, 0x036b: 0x3822, 0x036c: 0x3774, 0x036d: 0x37f8, 0x036e: 0x3750, 0x036f: 0x37d4, + 0x0370: 0x375c, 0x0371: 0x37e0, 0x0372: 0x3762, 0x0373: 0x37e6, 0x0374: 0x3768, 0x0375: 0x37ec, + 0x0378: 0x376e, 0x0379: 0x37f2, + // Block 0xe, offset 0x380 + 0x0387: 0x1ea0, + 0x0391: 0x812d, + 0x0392: 0x8132, 0x0393: 0x8132, 0x0394: 0x8132, 0x0395: 0x8132, 0x0396: 0x812d, 0x0397: 0x8132, + 0x0398: 0x8132, 0x0399: 0x8132, 0x039a: 0x812e, 0x039b: 0x812d, 0x039c: 0x8132, 0x039d: 0x8132, + 0x039e: 0x8132, 0x039f: 0x8132, 0x03a0: 0x8132, 0x03a1: 0x8132, 0x03a2: 0x812d, 0x03a3: 0x812d, + 0x03a4: 0x812d, 0x03a5: 0x812d, 0x03a6: 0x812d, 0x03a7: 0x812d, 0x03a8: 0x8132, 0x03a9: 0x8132, + 0x03aa: 0x812d, 0x03ab: 0x8132, 0x03ac: 0x8132, 0x03ad: 0x812e, 0x03ae: 0x8131, 0x03af: 0x8132, + 0x03b0: 0x8105, 0x03b1: 0x8106, 0x03b2: 0x8107, 0x03b3: 0x8108, 0x03b4: 0x8109, 0x03b5: 0x810a, + 0x03b6: 0x810b, 0x03b7: 0x810c, 0x03b8: 0x810d, 0x03b9: 0x810e, 0x03ba: 0x810e, 0x03bb: 0x810f, + 0x03bc: 0x8110, 0x03bd: 0x8111, 0x03bf: 0x8112, + // Block 0xf, offset 0x3c0 + 0x03c8: 0xa000, 0x03ca: 0xa000, 0x03cb: 0x8116, + 0x03cc: 0x8117, 0x03cd: 0x8118, 0x03ce: 0x8119, 0x03cf: 0x811a, 0x03d0: 0x811b, 0x03d1: 0x811c, + 0x03d2: 0x811d, 0x03d3: 0x9932, 0x03d4: 0x9932, 0x03d5: 0x992d, 0x03d6: 0x812d, 0x03d7: 0x8132, + 0x03d8: 0x8132, 0x03d9: 0x8132, 0x03da: 0x8132, 0x03db: 0x8132, 0x03dc: 0x812d, 0x03dd: 0x8132, + 0x03de: 0x8132, 0x03df: 0x812d, + 0x03f0: 0x811e, 0x03f5: 0x1ec3, + 0x03f6: 0x2152, 0x03f7: 0x218e, 0x03f8: 0x2189, + // Block 0x10, offset 0x400 + 0x0405: 0xa000, + 0x0406: 0x1943, 0x0407: 0xa000, 0x0408: 0x194a, 0x0409: 0xa000, 0x040a: 0x1951, 0x040b: 0xa000, + 0x040c: 0x1958, 0x040d: 0xa000, 0x040e: 0x195f, 0x0411: 0xa000, + 0x0412: 0x1966, + 0x0434: 0x8102, 0x0435: 0x9900, + 0x043a: 0xa000, 0x043b: 0x196d, + 0x043c: 0xa000, 0x043d: 0x1974, 0x043e: 0xa000, 0x043f: 0xa000, + // Block 0x11, offset 0x440 + 0x0440: 0x0069, 0x0441: 0x006b, 0x0442: 0x006f, 0x0443: 0x0083, 0x0444: 0x00f5, 0x0445: 0x00f8, + 0x0446: 0x0482, 0x0447: 0x0085, 0x0448: 0x0089, 0x0449: 0x008b, 0x044a: 0x0104, 0x044b: 0x0107, + 0x044c: 0x010a, 0x044d: 0x008f, 0x044f: 0x0097, 0x0450: 0x009b, 0x0451: 0x00e0, + 0x0452: 0x009f, 0x0453: 0x00fe, 0x0454: 0x0486, 0x0455: 0x048a, 0x0456: 0x00a1, 0x0457: 0x00a9, + 0x0458: 0x00ab, 0x0459: 0x0492, 0x045a: 0x0128, 0x045b: 0x00ad, 0x045c: 0x0496, 0x045d: 0x01bb, + 0x045e: 0x01be, 0x045f: 0x01c1, 0x0460: 0x01f7, 0x0461: 0x01fa, 0x0462: 0x0093, 0x0463: 0x00a5, + 0x0464: 0x00ab, 0x0465: 0x00ad, 0x0466: 0x01bb, 0x0467: 0x01be, 0x0468: 0x01e8, 0x0469: 0x01f7, + 0x046a: 0x01fa, + 0x0478: 0x0209, + // Block 0x12, offset 0x480 + 0x049b: 0x00fb, 0x049c: 0x0087, 0x049d: 0x0101, + 0x049e: 0x00d4, 0x049f: 0x010a, 0x04a0: 0x008d, 0x04a1: 0x010d, 0x04a2: 0x0110, 0x04a3: 0x0116, + 0x04a4: 0x011c, 0x04a5: 0x011f, 0x04a6: 0x0122, 0x04a7: 0x049a, 0x04a8: 0x0167, 0x04a9: 0x0125, + 0x04aa: 0x049e, 0x04ab: 0x016a, 0x04ac: 0x012e, 0x04ad: 0x012b, 0x04ae: 0x0131, 0x04af: 0x0134, + 0x04b0: 0x0137, 0x04b1: 0x013a, 0x04b2: 0x013d, 0x04b3: 0x0149, 0x04b4: 0x014c, 0x04b5: 0x00ec, + 0x04b6: 0x014f, 0x04b7: 0x0152, 0x04b8: 0x048e, 0x04b9: 0x0155, 0x04ba: 0x0158, 0x04bb: 0x00b5, + 0x04bc: 0x015b, 0x04bd: 0x015e, 0x04be: 0x0161, 0x04bf: 0x01cd, + // Block 0x13, offset 0x4c0 + 0x04c0: 0x2f7e, 0x04c1: 0x328a, 0x04c2: 0x2f88, 0x04c3: 0x3294, 0x04c4: 0x2f8d, 0x04c5: 0x3299, + 0x04c6: 0x2f92, 0x04c7: 0x329e, 0x04c8: 0x38b3, 0x04c9: 0x3a42, 0x04ca: 0x2fab, 0x04cb: 0x32b7, + 0x04cc: 0x2fb5, 0x04cd: 0x32c1, 0x04ce: 0x2fc4, 0x04cf: 0x32d0, 0x04d0: 0x2fba, 0x04d1: 0x32c6, + 0x04d2: 0x2fbf, 0x04d3: 0x32cb, 0x04d4: 0x38d6, 0x04d5: 0x3a65, 0x04d6: 0x38dd, 0x04d7: 0x3a6c, + 0x04d8: 0x3000, 0x04d9: 0x330c, 0x04da: 0x3005, 0x04db: 0x3311, 0x04dc: 0x38eb, 0x04dd: 0x3a7a, + 0x04de: 0x300a, 0x04df: 0x3316, 0x04e0: 0x3019, 0x04e1: 0x3325, 0x04e2: 0x3037, 0x04e3: 0x3343, + 0x04e4: 0x3046, 0x04e5: 0x3352, 0x04e6: 0x303c, 0x04e7: 0x3348, 0x04e8: 0x304b, 0x04e9: 0x3357, + 0x04ea: 0x3050, 0x04eb: 0x335c, 0x04ec: 0x3096, 0x04ed: 0x33a2, 0x04ee: 0x38f2, 0x04ef: 0x3a81, + 0x04f0: 0x30a0, 0x04f1: 0x33b1, 0x04f2: 0x30aa, 0x04f3: 0x33bb, 0x04f4: 0x30b4, 0x04f5: 0x33c5, + 0x04f6: 0x46ab, 0x04f7: 0x473c, 0x04f8: 0x38f9, 0x04f9: 0x3a88, 0x04fa: 0x30cd, 0x04fb: 0x33de, + 0x04fc: 0x30c8, 0x04fd: 0x33d9, 0x04fe: 0x30d2, 0x04ff: 0x33e3, + // Block 0x14, offset 0x500 + 0x0500: 0x30d7, 0x0501: 0x33e8, 0x0502: 0x30dc, 0x0503: 0x33ed, 0x0504: 0x30f0, 0x0505: 0x3401, + 0x0506: 0x30fa, 0x0507: 0x340b, 0x0508: 0x3109, 0x0509: 0x341a, 0x050a: 0x3104, 0x050b: 0x3415, + 0x050c: 0x391c, 0x050d: 0x3aab, 0x050e: 0x392a, 0x050f: 0x3ab9, 0x0510: 0x3931, 0x0511: 0x3ac0, + 0x0512: 0x3938, 0x0513: 0x3ac7, 0x0514: 0x3136, 0x0515: 0x3447, 0x0516: 0x313b, 0x0517: 0x344c, + 0x0518: 0x3145, 0x0519: 0x3456, 0x051a: 0x46d8, 0x051b: 0x4769, 0x051c: 0x397e, 0x051d: 0x3b0d, + 0x051e: 0x315e, 0x051f: 0x346f, 0x0520: 0x3168, 0x0521: 0x3479, 0x0522: 0x46e7, 0x0523: 0x4778, + 0x0524: 0x3985, 0x0525: 0x3b14, 0x0526: 0x398c, 0x0527: 0x3b1b, 0x0528: 0x3993, 0x0529: 0x3b22, + 0x052a: 0x3177, 0x052b: 0x3488, 0x052c: 0x3181, 0x052d: 0x3497, 0x052e: 0x3195, 0x052f: 0x34ab, + 0x0530: 0x3190, 0x0531: 0x34a6, 0x0532: 0x31d1, 0x0533: 0x34e7, 0x0534: 0x31e0, 0x0535: 0x34f6, + 0x0536: 0x31db, 0x0537: 0x34f1, 0x0538: 0x399a, 0x0539: 0x3b29, 0x053a: 0x39a1, 0x053b: 0x3b30, + 0x053c: 0x31e5, 0x053d: 0x34fb, 0x053e: 0x31ea, 0x053f: 0x3500, + // Block 0x15, offset 0x540 + 0x0540: 0x31ef, 0x0541: 0x3505, 0x0542: 0x31f4, 0x0543: 0x350a, 0x0544: 0x3203, 0x0545: 0x3519, + 0x0546: 0x31fe, 0x0547: 0x3514, 0x0548: 0x3208, 0x0549: 0x3523, 0x054a: 0x320d, 0x054b: 0x3528, + 0x054c: 0x3212, 0x054d: 0x352d, 0x054e: 0x3230, 0x054f: 0x354b, 0x0550: 0x3249, 0x0551: 0x3569, + 0x0552: 0x3258, 0x0553: 0x3578, 0x0554: 0x325d, 0x0555: 0x357d, 0x0556: 0x3361, 0x0557: 0x348d, + 0x0558: 0x351e, 0x0559: 0x355a, 0x055a: 0x1d1f, 0x055b: 0x42be, + 0x0560: 0x4688, 0x0561: 0x4719, 0x0562: 0x2f6a, 0x0563: 0x3276, + 0x0564: 0x385f, 0x0565: 0x39ee, 0x0566: 0x3858, 0x0567: 0x39e7, 0x0568: 0x386d, 0x0569: 0x39fc, + 0x056a: 0x3866, 0x056b: 0x39f5, 0x056c: 0x38a5, 0x056d: 0x3a34, 0x056e: 0x387b, 0x056f: 0x3a0a, + 0x0570: 0x3874, 0x0571: 0x3a03, 0x0572: 0x3889, 0x0573: 0x3a18, 0x0574: 0x3882, 0x0575: 0x3a11, + 0x0576: 0x38ac, 0x0577: 0x3a3b, 0x0578: 0x469c, 0x0579: 0x472d, 0x057a: 0x2fe7, 0x057b: 0x32f3, + 0x057c: 0x2fd3, 0x057d: 0x32df, 0x057e: 0x38c1, 0x057f: 0x3a50, + // Block 0x16, offset 0x580 + 0x0580: 0x38ba, 0x0581: 0x3a49, 0x0582: 0x38cf, 0x0583: 0x3a5e, 0x0584: 0x38c8, 0x0585: 0x3a57, + 0x0586: 0x38e4, 0x0587: 0x3a73, 0x0588: 0x3078, 0x0589: 0x3384, 0x058a: 0x308c, 0x058b: 0x3398, + 0x058c: 0x46ce, 0x058d: 0x475f, 0x058e: 0x311d, 0x058f: 0x342e, 0x0590: 0x3907, 0x0591: 0x3a96, + 0x0592: 0x3900, 0x0593: 0x3a8f, 0x0594: 0x3915, 0x0595: 0x3aa4, 0x0596: 0x390e, 0x0597: 0x3a9d, + 0x0598: 0x3970, 0x0599: 0x3aff, 0x059a: 0x3954, 0x059b: 0x3ae3, 0x059c: 0x394d, 0x059d: 0x3adc, + 0x059e: 0x3962, 0x059f: 0x3af1, 0x05a0: 0x395b, 0x05a1: 0x3aea, 0x05a2: 0x3969, 0x05a3: 0x3af8, + 0x05a4: 0x31cc, 0x05a5: 0x34e2, 0x05a6: 0x31ae, 0x05a7: 0x34c4, 0x05a8: 0x39cb, 0x05a9: 0x3b5a, + 0x05aa: 0x39c4, 0x05ab: 0x3b53, 0x05ac: 0x39d9, 0x05ad: 0x3b68, 0x05ae: 0x39d2, 0x05af: 0x3b61, + 0x05b0: 0x39e0, 0x05b1: 0x3b6f, 0x05b2: 0x3217, 0x05b3: 0x3532, 0x05b4: 0x323f, 0x05b5: 0x355f, + 0x05b6: 0x323a, 0x05b7: 0x3555, 0x05b8: 0x3226, 0x05b9: 0x3541, + // Block 0x17, offset 0x5c0 + 0x05c0: 0x47eb, 0x05c1: 0x47f1, 0x05c2: 0x4905, 0x05c3: 0x491d, 0x05c4: 0x490d, 0x05c5: 0x4925, + 0x05c6: 0x4915, 0x05c7: 0x492d, 0x05c8: 0x4791, 0x05c9: 0x4797, 0x05ca: 0x4875, 0x05cb: 0x488d, + 0x05cc: 0x487d, 0x05cd: 0x4895, 0x05ce: 0x4885, 0x05cf: 0x489d, 0x05d0: 0x47fd, 0x05d1: 0x4803, + 0x05d2: 0x3d9f, 0x05d3: 0x3daf, 0x05d4: 0x3da7, 0x05d5: 0x3db7, + 0x05d8: 0x479d, 0x05d9: 0x47a3, 0x05da: 0x3ccf, 0x05db: 0x3cdf, 0x05dc: 0x3cd7, 0x05dd: 0x3ce7, + 0x05e0: 0x4815, 0x05e1: 0x481b, 0x05e2: 0x4935, 0x05e3: 0x494d, + 0x05e4: 0x493d, 0x05e5: 0x4955, 0x05e6: 0x4945, 0x05e7: 0x495d, 0x05e8: 0x47a9, 0x05e9: 0x47af, + 0x05ea: 0x48a5, 0x05eb: 0x48bd, 0x05ec: 0x48ad, 0x05ed: 0x48c5, 0x05ee: 0x48b5, 0x05ef: 0x48cd, + 0x05f0: 0x482d, 0x05f1: 0x4833, 0x05f2: 0x3dff, 0x05f3: 0x3e17, 0x05f4: 0x3e07, 0x05f5: 0x3e1f, + 0x05f6: 0x3e0f, 0x05f7: 0x3e27, 0x05f8: 0x47b5, 0x05f9: 0x47bb, 0x05fa: 0x3cff, 0x05fb: 0x3d17, + 0x05fc: 0x3d07, 0x05fd: 0x3d1f, 0x05fe: 0x3d0f, 0x05ff: 0x3d27, + // Block 0x18, offset 0x600 + 0x0600: 0x4839, 0x0601: 0x483f, 0x0602: 0x3e2f, 0x0603: 0x3e3f, 0x0604: 0x3e37, 0x0605: 0x3e47, + 0x0608: 0x47c1, 0x0609: 0x47c7, 0x060a: 0x3d2f, 0x060b: 0x3d3f, + 0x060c: 0x3d37, 0x060d: 0x3d47, 0x0610: 0x484b, 0x0611: 0x4851, + 0x0612: 0x3e67, 0x0613: 0x3e7f, 0x0614: 0x3e6f, 0x0615: 0x3e87, 0x0616: 0x3e77, 0x0617: 0x3e8f, + 0x0619: 0x47cd, 0x061b: 0x3d4f, 0x061d: 0x3d57, + 0x061f: 0x3d5f, 0x0620: 0x4863, 0x0621: 0x4869, 0x0622: 0x4965, 0x0623: 0x497d, + 0x0624: 0x496d, 0x0625: 0x4985, 0x0626: 0x4975, 0x0627: 0x498d, 0x0628: 0x47d3, 0x0629: 0x47d9, + 0x062a: 0x48d5, 0x062b: 0x48ed, 0x062c: 0x48dd, 0x062d: 0x48f5, 0x062e: 0x48e5, 0x062f: 0x48fd, + 0x0630: 0x47df, 0x0631: 0x4305, 0x0632: 0x3678, 0x0633: 0x430b, 0x0634: 0x4809, 0x0635: 0x4311, + 0x0636: 0x368a, 0x0637: 0x4317, 0x0638: 0x36a8, 0x0639: 0x431d, 0x063a: 0x36c0, 0x063b: 0x4323, + 0x063c: 0x4857, 0x063d: 0x4329, + // Block 0x19, offset 0x640 + 0x0640: 0x3d87, 0x0641: 0x3d8f, 0x0642: 0x416b, 0x0643: 0x4189, 0x0644: 0x4175, 0x0645: 0x4193, + 0x0646: 0x417f, 0x0647: 0x419d, 0x0648: 0x3cbf, 0x0649: 0x3cc7, 0x064a: 0x40b7, 0x064b: 0x40d5, + 0x064c: 0x40c1, 0x064d: 0x40df, 0x064e: 0x40cb, 0x064f: 0x40e9, 0x0650: 0x3dcf, 0x0651: 0x3dd7, + 0x0652: 0x41a7, 0x0653: 0x41c5, 0x0654: 0x41b1, 0x0655: 0x41cf, 0x0656: 0x41bb, 0x0657: 0x41d9, + 0x0658: 0x3cef, 0x0659: 0x3cf7, 0x065a: 0x40f3, 0x065b: 0x4111, 0x065c: 0x40fd, 0x065d: 0x411b, + 0x065e: 0x4107, 0x065f: 0x4125, 0x0660: 0x3ea7, 0x0661: 0x3eaf, 0x0662: 0x41e3, 0x0663: 0x4201, + 0x0664: 0x41ed, 0x0665: 0x420b, 0x0666: 0x41f7, 0x0667: 0x4215, 0x0668: 0x3d67, 0x0669: 0x3d6f, + 0x066a: 0x412f, 0x066b: 0x414d, 0x066c: 0x4139, 0x066d: 0x4157, 0x066e: 0x4143, 0x066f: 0x4161, + 0x0670: 0x366c, 0x0671: 0x3666, 0x0672: 0x3d77, 0x0673: 0x3672, 0x0674: 0x3d7f, + 0x0676: 0x47f7, 0x0677: 0x3d97, 0x0678: 0x35dc, 0x0679: 0x35d6, 0x067a: 0x35ca, 0x067b: 0x42d5, + 0x067c: 0x35e2, 0x067d: 0x426e, 0x067e: 0x01d0, 0x067f: 0x426e, + // Block 0x1a, offset 0x680 + 0x0680: 0x4287, 0x0681: 0x4469, 0x0682: 0x3dbf, 0x0683: 0x3684, 0x0684: 0x3dc7, + 0x0686: 0x4821, 0x0687: 0x3ddf, 0x0688: 0x35e8, 0x0689: 0x42db, 0x068a: 0x35f4, 0x068b: 0x42e1, + 0x068c: 0x3600, 0x068d: 0x4470, 0x068e: 0x4477, 0x068f: 0x447e, 0x0690: 0x369c, 0x0691: 0x3696, + 0x0692: 0x3de7, 0x0693: 0x44cb, 0x0696: 0x36a2, 0x0697: 0x3df7, + 0x0698: 0x3618, 0x0699: 0x3612, 0x069a: 0x3606, 0x069b: 0x42e7, 0x069d: 0x4485, + 0x069e: 0x448c, 0x069f: 0x4493, 0x06a0: 0x36d2, 0x06a1: 0x36cc, 0x06a2: 0x3e4f, 0x06a3: 0x44d3, + 0x06a4: 0x36b4, 0x06a5: 0x36ba, 0x06a6: 0x36d8, 0x06a7: 0x3e5f, 0x06a8: 0x3648, 0x06a9: 0x3642, + 0x06aa: 0x3636, 0x06ab: 0x42f3, 0x06ac: 0x3630, 0x06ad: 0x445b, 0x06ae: 0x4462, 0x06af: 0x0081, + 0x06b2: 0x3e97, 0x06b3: 0x36de, 0x06b4: 0x3e9f, + 0x06b6: 0x486f, 0x06b7: 0x3eb7, 0x06b8: 0x3624, 0x06b9: 0x42ed, 0x06ba: 0x3654, 0x06bb: 0x42ff, + 0x06bc: 0x3660, 0x06bd: 0x4241, 0x06be: 0x4273, + // Block 0x1b, offset 0x6c0 + 0x06c0: 0x1d17, 0x06c1: 0x1d1b, 0x06c2: 0x0047, 0x06c3: 0x1d93, 0x06c5: 0x1d27, + 0x06c6: 0x1d2b, 0x06c7: 0x00e9, 0x06c9: 0x1d97, 0x06ca: 0x008f, 0x06cb: 0x0051, + 0x06cc: 0x0051, 0x06cd: 0x0051, 0x06ce: 0x0091, 0x06cf: 0x00da, 0x06d0: 0x0053, 0x06d1: 0x0053, + 0x06d2: 0x0059, 0x06d3: 0x0099, 0x06d5: 0x005d, 0x06d6: 0x1acc, + 0x06d9: 0x0061, 0x06da: 0x0063, 0x06db: 0x0065, 0x06dc: 0x0065, 0x06dd: 0x0065, + 0x06e0: 0x1ade, 0x06e1: 0x1d07, 0x06e2: 0x1ae7, + 0x06e4: 0x0075, 0x06e6: 0x01b5, 0x06e8: 0x0075, + 0x06ea: 0x0057, 0x06eb: 0x42b9, 0x06ec: 0x0045, 0x06ed: 0x0047, 0x06ef: 0x008b, + 0x06f0: 0x004b, 0x06f1: 0x004d, 0x06f3: 0x005b, 0x06f4: 0x009f, 0x06f5: 0x020c, + 0x06f6: 0x020f, 0x06f7: 0x0212, 0x06f8: 0x0215, 0x06f9: 0x0093, 0x06fb: 0x1cd7, + 0x06fc: 0x01e5, 0x06fd: 0x01be, 0x06fe: 0x0176, 0x06ff: 0x019d, + // Block 0x1c, offset 0x700 + 0x0700: 0x04d2, 0x0705: 0x0049, + 0x0706: 0x0089, 0x0707: 0x008b, 0x0708: 0x0093, 0x0709: 0x0095, + 0x0710: 0x236d, 0x0711: 0x2379, + 0x0712: 0x242d, 0x0713: 0x2355, 0x0714: 0x23d9, 0x0715: 0x2361, 0x0716: 0x23df, 0x0717: 0x23f7, + 0x0718: 0x2403, 0x0719: 0x2367, 0x071a: 0x2409, 0x071b: 0x2373, 0x071c: 0x23fd, 0x071d: 0x240f, + 0x071e: 0x2415, 0x071f: 0x1dfb, 0x0720: 0x0053, 0x0721: 0x1a99, 0x0722: 0x1ce3, 0x0723: 0x1aa2, + 0x0724: 0x006d, 0x0725: 0x1aea, 0x0726: 0x1d0f, 0x0727: 0x1e87, 0x0728: 0x1aa5, 0x0729: 0x0071, + 0x072a: 0x1af6, 0x072b: 0x1d13, 0x072c: 0x0059, 0x072d: 0x0047, 0x072e: 0x0049, 0x072f: 0x005b, + 0x0730: 0x0093, 0x0731: 0x1b23, 0x0732: 0x1d57, 0x0733: 0x1b2c, 0x0734: 0x00ad, 0x0735: 0x1ba1, + 0x0736: 0x1d8b, 0x0737: 0x1e9b, 0x0738: 0x1b2f, 0x0739: 0x00b1, 0x073a: 0x1ba4, 0x073b: 0x1d8f, + 0x073c: 0x0099, 0x073d: 0x0087, 0x073e: 0x0089, 0x073f: 0x009b, + // Block 0x1d, offset 0x740 + 0x0741: 0x3bed, 0x0743: 0xa000, 0x0744: 0x3bf4, 0x0745: 0xa000, + 0x0747: 0x3bfb, 0x0748: 0xa000, 0x0749: 0x3c02, + 0x074d: 0xa000, + 0x0760: 0x2f4c, 0x0761: 0xa000, 0x0762: 0x3c10, + 0x0764: 0xa000, 0x0765: 0xa000, + 0x076d: 0x3c09, 0x076e: 0x2f47, 0x076f: 0x2f51, + 0x0770: 0x3c17, 0x0771: 0x3c1e, 0x0772: 0xa000, 0x0773: 0xa000, 0x0774: 0x3c25, 0x0775: 0x3c2c, + 0x0776: 0xa000, 0x0777: 0xa000, 0x0778: 0x3c33, 0x0779: 0x3c3a, 0x077a: 0xa000, 0x077b: 0xa000, + 0x077c: 0xa000, 0x077d: 0xa000, + // Block 0x1e, offset 0x780 + 0x0780: 0x3c41, 0x0781: 0x3c48, 0x0782: 0xa000, 0x0783: 0xa000, 0x0784: 0x3c5d, 0x0785: 0x3c64, + 0x0786: 0xa000, 0x0787: 0xa000, 0x0788: 0x3c6b, 0x0789: 0x3c72, + 0x0791: 0xa000, + 0x0792: 0xa000, + 0x07a2: 0xa000, + 0x07a8: 0xa000, 0x07a9: 0xa000, + 0x07ab: 0xa000, 0x07ac: 0x3c87, 0x07ad: 0x3c8e, 0x07ae: 0x3c95, 0x07af: 0x3c9c, + 0x07b2: 0xa000, 0x07b3: 0xa000, 0x07b4: 0xa000, 0x07b5: 0xa000, + // Block 0x1f, offset 0x7c0 + 0x07e0: 0x0023, 0x07e1: 0x0025, 0x07e2: 0x0027, 0x07e3: 0x0029, + 0x07e4: 0x002b, 0x07e5: 0x002d, 0x07e6: 0x002f, 0x07e7: 0x0031, 0x07e8: 0x0033, 0x07e9: 0x19c1, + 0x07ea: 0x19c4, 0x07eb: 0x19c7, 0x07ec: 0x19ca, 0x07ed: 0x19cd, 0x07ee: 0x19d0, 0x07ef: 0x19d3, + 0x07f0: 0x19d6, 0x07f1: 0x19d9, 0x07f2: 0x19dc, 0x07f3: 0x19e5, 0x07f4: 0x1ba7, 0x07f5: 0x1bab, + 0x07f6: 0x1baf, 0x07f7: 0x1bb3, 0x07f8: 0x1bb7, 0x07f9: 0x1bbb, 0x07fa: 0x1bbf, 0x07fb: 0x1bc3, + 0x07fc: 0x1bc7, 0x07fd: 0x1dbf, 0x07fe: 0x1dc4, 0x07ff: 0x1dc9, + // Block 0x20, offset 0x800 + 0x0800: 0x1dce, 0x0801: 0x1dd3, 0x0802: 0x1dd8, 0x0803: 0x1ddd, 0x0804: 0x1de2, 0x0805: 0x1de7, + 0x0806: 0x1dec, 0x0807: 0x1df1, 0x0808: 0x19be, 0x0809: 0x19e2, 0x080a: 0x1a06, 0x080b: 0x1a2a, + 0x080c: 0x1a4e, 0x080d: 0x1a57, 0x080e: 0x1a5d, 0x080f: 0x1a63, 0x0810: 0x1a69, 0x0811: 0x1c9f, + 0x0812: 0x1ca3, 0x0813: 0x1ca7, 0x0814: 0x1cab, 0x0815: 0x1caf, 0x0816: 0x1cb3, 0x0817: 0x1cb7, + 0x0818: 0x1cbb, 0x0819: 0x1cbf, 0x081a: 0x1cc3, 0x081b: 0x1cc7, 0x081c: 0x1c33, 0x081d: 0x1c37, + 0x081e: 0x1c3b, 0x081f: 0x1c3f, 0x0820: 0x1c43, 0x0821: 0x1c47, 0x0822: 0x1c4b, 0x0823: 0x1c4f, + 0x0824: 0x1c53, 0x0825: 0x1c57, 0x0826: 0x1c5b, 0x0827: 0x1c5f, 0x0828: 0x1c63, 0x0829: 0x1c67, + 0x082a: 0x1c6b, 0x082b: 0x1c6f, 0x082c: 0x1c73, 0x082d: 0x1c77, 0x082e: 0x1c7b, 0x082f: 0x1c7f, + 0x0830: 0x1c83, 0x0831: 0x1c87, 0x0832: 0x1c8b, 0x0833: 0x1c8f, 0x0834: 0x1c93, 0x0835: 0x1c97, + 0x0836: 0x0043, 0x0837: 0x0045, 0x0838: 0x0047, 0x0839: 0x0049, 0x083a: 0x004b, 0x083b: 0x004d, + 0x083c: 0x004f, 0x083d: 0x0051, 0x083e: 0x0053, 0x083f: 0x0055, + // Block 0x21, offset 0x840 + 0x0840: 0x072e, 0x0841: 0x0752, 0x0842: 0x075e, 0x0843: 0x076e, 0x0844: 0x0776, 0x0845: 0x0782, + 0x0846: 0x078a, 0x0847: 0x0792, 0x0848: 0x079e, 0x0849: 0x07f2, 0x084a: 0x080a, 0x084b: 0x081a, + 0x084c: 0x082a, 0x084d: 0x083a, 0x084e: 0x084a, 0x084f: 0x086a, 0x0850: 0x086e, 0x0851: 0x0872, + 0x0852: 0x08a6, 0x0853: 0x08ce, 0x0854: 0x08de, 0x0855: 0x08e6, 0x0856: 0x08ea, 0x0857: 0x08f6, + 0x0858: 0x0912, 0x0859: 0x0916, 0x085a: 0x092e, 0x085b: 0x0932, 0x085c: 0x093a, 0x085d: 0x094a, + 0x085e: 0x09e6, 0x085f: 0x09fa, 0x0860: 0x0a3a, 0x0861: 0x0a4e, 0x0862: 0x0a56, 0x0863: 0x0a5a, + 0x0864: 0x0a6a, 0x0865: 0x0a86, 0x0866: 0x0ab2, 0x0867: 0x0abe, 0x0868: 0x0ade, 0x0869: 0x0aea, + 0x086a: 0x0aee, 0x086b: 0x0af2, 0x086c: 0x0b0a, 0x086d: 0x0b0e, 0x086e: 0x0b3a, 0x086f: 0x0b46, + 0x0870: 0x0b4e, 0x0871: 0x0b56, 0x0872: 0x0b66, 0x0873: 0x0b6e, 0x0874: 0x0b76, 0x0875: 0x0ba2, + 0x0876: 0x0ba6, 0x0877: 0x0bae, 0x0878: 0x0bb2, 0x0879: 0x0bba, 0x087a: 0x0bc2, 0x087b: 0x0bd2, + 0x087c: 0x0bee, 0x087d: 0x0c66, 0x087e: 0x0c7a, 0x087f: 0x0c7e, + // Block 0x22, offset 0x880 + 0x0880: 0x0cfe, 0x0881: 0x0d02, 0x0882: 0x0d16, 0x0883: 0x0d1a, 0x0884: 0x0d22, 0x0885: 0x0d2a, + 0x0886: 0x0d32, 0x0887: 0x0d3e, 0x0888: 0x0d66, 0x0889: 0x0d76, 0x088a: 0x0d8a, 0x088b: 0x0dfa, + 0x088c: 0x0e06, 0x088d: 0x0e16, 0x088e: 0x0e22, 0x088f: 0x0e2e, 0x0890: 0x0e36, 0x0891: 0x0e3a, + 0x0892: 0x0e3e, 0x0893: 0x0e42, 0x0894: 0x0e46, 0x0895: 0x0efe, 0x0896: 0x0f46, 0x0897: 0x0f52, + 0x0898: 0x0f56, 0x0899: 0x0f5a, 0x089a: 0x0f5e, 0x089b: 0x0f66, 0x089c: 0x0f6a, 0x089d: 0x0f7e, + 0x089e: 0x0f9a, 0x089f: 0x0fa2, 0x08a0: 0x0fe2, 0x08a1: 0x0fe6, 0x08a2: 0x0fee, 0x08a3: 0x0ff2, + 0x08a4: 0x0ffa, 0x08a5: 0x0ffe, 0x08a6: 0x1022, 0x08a7: 0x1026, 0x08a8: 0x1042, 0x08a9: 0x1046, + 0x08aa: 0x104a, 0x08ab: 0x104e, 0x08ac: 0x1062, 0x08ad: 0x1086, 0x08ae: 0x108a, 0x08af: 0x108e, + 0x08b0: 0x10b2, 0x08b1: 0x10f2, 0x08b2: 0x10f6, 0x08b3: 0x1116, 0x08b4: 0x1126, 0x08b5: 0x112e, + 0x08b6: 0x114e, 0x08b7: 0x1172, 0x08b8: 0x11b6, 0x08b9: 0x11be, 0x08ba: 0x11d2, 0x08bb: 0x11de, + 0x08bc: 0x11e6, 0x08bd: 0x11ee, 0x08be: 0x11f2, 0x08bf: 0x11f6, + // Block 0x23, offset 0x8c0 + 0x08c0: 0x120e, 0x08c1: 0x1212, 0x08c2: 0x122e, 0x08c3: 0x1236, 0x08c4: 0x123e, 0x08c5: 0x1242, + 0x08c6: 0x124e, 0x08c7: 0x1256, 0x08c8: 0x125a, 0x08c9: 0x125e, 0x08ca: 0x1266, 0x08cb: 0x126a, + 0x08cc: 0x130a, 0x08cd: 0x131e, 0x08ce: 0x1352, 0x08cf: 0x1356, 0x08d0: 0x135e, 0x08d1: 0x138a, + 0x08d2: 0x1392, 0x08d3: 0x139a, 0x08d4: 0x13a2, 0x08d5: 0x13de, 0x08d6: 0x13e2, 0x08d7: 0x13ea, + 0x08d8: 0x13ee, 0x08d9: 0x13f2, 0x08da: 0x141e, 0x08db: 0x1422, 0x08dc: 0x142a, 0x08dd: 0x143e, + 0x08de: 0x1442, 0x08df: 0x145e, 0x08e0: 0x1466, 0x08e1: 0x146a, 0x08e2: 0x148e, 0x08e3: 0x14ae, + 0x08e4: 0x14be, 0x08e5: 0x14c2, 0x08e6: 0x14ca, 0x08e7: 0x14f6, 0x08e8: 0x14fa, 0x08e9: 0x150a, + 0x08ea: 0x152e, 0x08eb: 0x153a, 0x08ec: 0x154a, 0x08ed: 0x1562, 0x08ee: 0x156a, 0x08ef: 0x156e, + 0x08f0: 0x1572, 0x08f1: 0x1576, 0x08f2: 0x1582, 0x08f3: 0x1586, 0x08f4: 0x158e, 0x08f5: 0x15aa, + 0x08f6: 0x15ae, 0x08f7: 0x15b2, 0x08f8: 0x15ca, 0x08f9: 0x15ce, 0x08fa: 0x15d6, 0x08fb: 0x15ea, + 0x08fc: 0x15ee, 0x08fd: 0x15f2, 0x08fe: 0x15fa, 0x08ff: 0x15fe, + // Block 0x24, offset 0x900 + 0x0906: 0xa000, 0x090b: 0xa000, + 0x090c: 0x3eef, 0x090d: 0xa000, 0x090e: 0x3ef7, 0x090f: 0xa000, 0x0910: 0x3eff, 0x0911: 0xa000, + 0x0912: 0x3f07, 0x0913: 0xa000, 0x0914: 0x3f0f, 0x0915: 0xa000, 0x0916: 0x3f17, 0x0917: 0xa000, + 0x0918: 0x3f1f, 0x0919: 0xa000, 0x091a: 0x3f27, 0x091b: 0xa000, 0x091c: 0x3f2f, 0x091d: 0xa000, + 0x091e: 0x3f37, 0x091f: 0xa000, 0x0920: 0x3f3f, 0x0921: 0xa000, 0x0922: 0x3f47, + 0x0924: 0xa000, 0x0925: 0x3f4f, 0x0926: 0xa000, 0x0927: 0x3f57, 0x0928: 0xa000, 0x0929: 0x3f5f, + 0x092f: 0xa000, + 0x0930: 0x3f67, 0x0931: 0x3f6f, 0x0932: 0xa000, 0x0933: 0x3f77, 0x0934: 0x3f7f, 0x0935: 0xa000, + 0x0936: 0x3f87, 0x0937: 0x3f8f, 0x0938: 0xa000, 0x0939: 0x3f97, 0x093a: 0x3f9f, 0x093b: 0xa000, + 0x093c: 0x3fa7, 0x093d: 0x3faf, + // Block 0x25, offset 0x940 + 0x0954: 0x3ee7, + 0x0959: 0x9903, 0x095a: 0x9903, 0x095b: 0x42c3, 0x095c: 0x42c9, 0x095d: 0xa000, + 0x095e: 0x3fb7, 0x095f: 0x285c, + 0x0966: 0xa000, + 0x096b: 0xa000, 0x096c: 0x3fc7, 0x096d: 0xa000, 0x096e: 0x3fcf, 0x096f: 0xa000, + 0x0970: 0x3fd7, 0x0971: 0xa000, 0x0972: 0x3fdf, 0x0973: 0xa000, 0x0974: 0x3fe7, 0x0975: 0xa000, + 0x0976: 0x3fef, 0x0977: 0xa000, 0x0978: 0x3ff7, 0x0979: 0xa000, 0x097a: 0x3fff, 0x097b: 0xa000, + 0x097c: 0x4007, 0x097d: 0xa000, 0x097e: 0x400f, 0x097f: 0xa000, + // Block 0x26, offset 0x980 + 0x0980: 0x4017, 0x0981: 0xa000, 0x0982: 0x401f, 0x0984: 0xa000, 0x0985: 0x4027, + 0x0986: 0xa000, 0x0987: 0x402f, 0x0988: 0xa000, 0x0989: 0x4037, + 0x098f: 0xa000, 0x0990: 0x403f, 0x0991: 0x4047, + 0x0992: 0xa000, 0x0993: 0x404f, 0x0994: 0x4057, 0x0995: 0xa000, 0x0996: 0x405f, 0x0997: 0x4067, + 0x0998: 0xa000, 0x0999: 0x406f, 0x099a: 0x4077, 0x099b: 0xa000, 0x099c: 0x407f, 0x099d: 0x4087, + 0x09af: 0xa000, + 0x09b0: 0xa000, 0x09b1: 0xa000, 0x09b2: 0xa000, 0x09b4: 0x3fbf, + 0x09b7: 0x408f, 0x09b8: 0x4097, 0x09b9: 0x409f, 0x09ba: 0x40a7, + 0x09bd: 0xa000, 0x09be: 0x40af, 0x09bf: 0x2871, + // Block 0x27, offset 0x9c0 + 0x09c0: 0x03a6, 0x09c1: 0x03aa, 0x09c2: 0x047a, 0x09c3: 0x047e, 0x09c4: 0x03ae, 0x09c5: 0x03b2, + 0x09c6: 0x03b6, 0x09c7: 0x0412, 0x09c8: 0x0416, 0x09c9: 0x041a, 0x09ca: 0x041e, 0x09cb: 0x0422, + 0x09cc: 0x0426, 0x09cd: 0x042a, 0x09ce: 0x042e, + 0x09d2: 0x072e, 0x09d3: 0x078a, 0x09d4: 0x073a, 0x09d5: 0x09ea, 0x09d6: 0x073e, 0x09d7: 0x0756, + 0x09d8: 0x0742, 0x09d9: 0x1002, 0x09da: 0x0776, 0x09db: 0x074a, 0x09dc: 0x0732, 0x09dd: 0x0a6e, + 0x09de: 0x09fe, 0x09df: 0x079e, + // Block 0x28, offset 0xa00 + 0x0a00: 0x2193, 0x0a01: 0x2199, 0x0a02: 0x219f, 0x0a03: 0x21a5, 0x0a04: 0x21ab, 0x0a05: 0x21b1, + 0x0a06: 0x21b7, 0x0a07: 0x21bd, 0x0a08: 0x21c3, 0x0a09: 0x21c9, 0x0a0a: 0x21cf, 0x0a0b: 0x21d5, + 0x0a0c: 0x21db, 0x0a0d: 0x21e1, 0x0a0e: 0x28ce, 0x0a0f: 0x28d7, 0x0a10: 0x28e0, 0x0a11: 0x28e9, + 0x0a12: 0x28f2, 0x0a13: 0x28fb, 0x0a14: 0x2904, 0x0a15: 0x290d, 0x0a16: 0x2916, 0x0a17: 0x2928, + 0x0a18: 0x2931, 0x0a19: 0x293a, 0x0a1a: 0x2943, 0x0a1b: 0x294c, 0x0a1c: 0x291f, 0x0a1d: 0x2d71, + 0x0a1e: 0x2ca2, 0x0a20: 0x21e7, 0x0a21: 0x21ff, 0x0a22: 0x21f3, 0x0a23: 0x2247, + 0x0a24: 0x2205, 0x0a25: 0x2223, 0x0a26: 0x21ed, 0x0a27: 0x221d, 0x0a28: 0x21f9, 0x0a29: 0x222f, + 0x0a2a: 0x225f, 0x0a2b: 0x227d, 0x0a2c: 0x2277, 0x0a2d: 0x226b, 0x0a2e: 0x22b9, 0x0a2f: 0x224d, + 0x0a30: 0x2259, 0x0a31: 0x2271, 0x0a32: 0x2265, 0x0a33: 0x228f, 0x0a34: 0x223b, 0x0a35: 0x2283, + 0x0a36: 0x22ad, 0x0a37: 0x2295, 0x0a38: 0x2229, 0x0a39: 0x220b, 0x0a3a: 0x2241, 0x0a3b: 0x2253, + 0x0a3c: 0x2289, 0x0a3d: 0x2211, 0x0a3e: 0x22b3, 0x0a3f: 0x2235, + // Block 0x29, offset 0xa40 + 0x0a40: 0x229b, 0x0a41: 0x2217, 0x0a42: 0x22a1, 0x0a43: 0x22a7, 0x0a44: 0x099e, 0x0a45: 0x0b72, + 0x0a46: 0x0d16, 0x0a47: 0x1136, + 0x0a50: 0x1d03, 0x0a51: 0x19e8, + 0x0a52: 0x19eb, 0x0a53: 0x19ee, 0x0a54: 0x19f1, 0x0a55: 0x19f4, 0x0a56: 0x19f7, 0x0a57: 0x19fa, + 0x0a58: 0x19fd, 0x0a59: 0x1a00, 0x0a5a: 0x1a09, 0x0a5b: 0x1a0c, 0x0a5c: 0x1a0f, 0x0a5d: 0x1a12, + 0x0a5e: 0x1a15, 0x0a5f: 0x1a18, 0x0a60: 0x030a, 0x0a61: 0x0312, 0x0a62: 0x0316, 0x0a63: 0x031e, + 0x0a64: 0x0322, 0x0a65: 0x0326, 0x0a66: 0x032e, 0x0a67: 0x0336, 0x0a68: 0x033a, 0x0a69: 0x0342, + 0x0a6a: 0x0346, 0x0a6b: 0x034a, 0x0a6c: 0x034e, 0x0a6d: 0x0352, 0x0a6e: 0x27d0, 0x0a6f: 0x27d7, + 0x0a70: 0x27de, 0x0a71: 0x27e5, 0x0a72: 0x27ec, 0x0a73: 0x27f3, 0x0a74: 0x27fa, 0x0a75: 0x2801, + 0x0a76: 0x280f, 0x0a77: 0x2816, 0x0a78: 0x281d, 0x0a79: 0x2824, 0x0a7a: 0x282b, 0x0a7b: 0x2832, + 0x0a7c: 0x2cc1, 0x0a7d: 0x2b36, 0x0a7e: 0x2808, + // Block 0x2a, offset 0xa80 + 0x0a80: 0x072e, 0x0a81: 0x078a, 0x0a82: 0x073a, 0x0a83: 0x09ea, 0x0a84: 0x078e, 0x0a85: 0x081e, + 0x0a86: 0x0736, 0x0a87: 0x081a, 0x0a88: 0x077a, 0x0a89: 0x08f6, 0x0a8a: 0x0d76, 0x0a8b: 0x0efe, + 0x0a8c: 0x0e46, 0x0a8d: 0x0d8a, 0x0a8e: 0x14ca, 0x0a8f: 0x09fa, 0x0a90: 0x0d3e, 0x0a91: 0x0dba, + 0x0a92: 0x0d7a, 0x0a93: 0x10ba, 0x0a94: 0x096a, 0x0a95: 0x0f72, 0x0a96: 0x13f6, 0x0a97: 0x10ce, + 0x0a98: 0x08b2, 0x0a99: 0x10fe, 0x0a9a: 0x100a, 0x0a9b: 0x0a86, 0x0a9c: 0x147e, 0x0a9d: 0x07ee, + 0x0a9e: 0x091a, 0x0a9f: 0x0e66, 0x0aa0: 0x1592, 0x0aa1: 0x07b2, 0x0aa2: 0x0842, 0x0aa3: 0x0e0a, + 0x0aa4: 0x073e, 0x0aa5: 0x0756, 0x0aa6: 0x0742, 0x0aa7: 0x0b4a, 0x0aa8: 0x095e, 0x0aa9: 0x08ee, + 0x0aaa: 0x0ac6, 0x0aab: 0x0aba, 0x0aac: 0x105a, 0x0aad: 0x07ae, 0x0aae: 0x140a, 0x0aaf: 0x090a, + 0x0ab0: 0x0a62, 0x0ab1: 0x1a1b, 0x0ab2: 0x1a1e, 0x0ab3: 0x1a21, 0x0ab4: 0x1a24, 0x0ab5: 0x1a2d, + 0x0ab6: 0x1a30, 0x0ab7: 0x1a33, 0x0ab8: 0x1a36, 0x0ab9: 0x1a39, 0x0aba: 0x1a3c, 0x0abb: 0x1a3f, + 0x0abc: 0x1a42, 0x0abd: 0x1a45, 0x0abe: 0x1a48, 0x0abf: 0x1a51, + // Block 0x2b, offset 0xac0 + 0x0ac0: 0x1e05, 0x0ac1: 0x1e14, 0x0ac2: 0x1e23, 0x0ac3: 0x1e32, 0x0ac4: 0x1e41, 0x0ac5: 0x1e50, + 0x0ac6: 0x1e5f, 0x0ac7: 0x1e6e, 0x0ac8: 0x1e7d, 0x0ac9: 0x22cb, 0x0aca: 0x22dd, 0x0acb: 0x22ef, + 0x0acc: 0x1a93, 0x0acd: 0x1d43, 0x0ace: 0x1b11, 0x0acf: 0x1ce7, 0x0ad0: 0x053a, 0x0ad1: 0x0542, + 0x0ad2: 0x054a, 0x0ad3: 0x0552, 0x0ad4: 0x055a, 0x0ad5: 0x055e, 0x0ad6: 0x0562, 0x0ad7: 0x0566, + 0x0ad8: 0x056a, 0x0ad9: 0x056e, 0x0ada: 0x0572, 0x0adb: 0x0576, 0x0adc: 0x057a, 0x0add: 0x057e, + 0x0ade: 0x0582, 0x0adf: 0x0586, 0x0ae0: 0x058a, 0x0ae1: 0x0592, 0x0ae2: 0x0596, 0x0ae3: 0x059a, + 0x0ae4: 0x059e, 0x0ae5: 0x05a2, 0x0ae6: 0x05a6, 0x0ae7: 0x05aa, 0x0ae8: 0x05ae, 0x0ae9: 0x05b2, + 0x0aea: 0x05b6, 0x0aeb: 0x05ba, 0x0aec: 0x05be, 0x0aed: 0x05c2, 0x0aee: 0x05c6, 0x0aef: 0x05ca, + 0x0af0: 0x05ce, 0x0af1: 0x05d2, 0x0af2: 0x05d6, 0x0af3: 0x05de, 0x0af4: 0x05e6, 0x0af5: 0x05ee, + 0x0af6: 0x05f2, 0x0af7: 0x05f6, 0x0af8: 0x05fa, 0x0af9: 0x05fe, 0x0afa: 0x0602, 0x0afb: 0x0606, + 0x0afc: 0x060a, 0x0afd: 0x060e, 0x0afe: 0x0612, + // Block 0x2c, offset 0xb00 + 0x0b00: 0x2cd1, 0x0b01: 0x2b5d, 0x0b02: 0x2ce1, 0x0b03: 0x2a28, 0x0b04: 0x2edb, 0x0b05: 0x2a32, + 0x0b06: 0x2a3c, 0x0b07: 0x2f1f, 0x0b08: 0x2b6a, 0x0b09: 0x2a46, 0x0b0a: 0x2a50, 0x0b0b: 0x2a5a, + 0x0b0c: 0x2b91, 0x0b0d: 0x2b9e, 0x0b0e: 0x2b77, 0x0b0f: 0x2b84, 0x0b10: 0x2eb1, 0x0b11: 0x2bab, + 0x0b12: 0x2bb8, 0x0b13: 0x2d83, 0x0b14: 0x2863, 0x0b15: 0x2d96, 0x0b16: 0x2da9, 0x0b17: 0x2cf1, + 0x0b18: 0x2bc5, 0x0b19: 0x2dbc, 0x0b1a: 0x2dcf, 0x0b1b: 0x2bd2, 0x0b1c: 0x2a64, 0x0b1d: 0x2a6e, + 0x0b1e: 0x2ebf, 0x0b1f: 0x2bdf, 0x0b20: 0x2d01, 0x0b21: 0x2eec, 0x0b22: 0x2a78, 0x0b23: 0x2a82, + 0x0b24: 0x2bec, 0x0b25: 0x2a8c, 0x0b26: 0x2a96, 0x0b27: 0x2878, 0x0b28: 0x287f, 0x0b29: 0x2aa0, + 0x0b2a: 0x2aaa, 0x0b2b: 0x2de2, 0x0b2c: 0x2bf9, 0x0b2d: 0x2d11, 0x0b2e: 0x2df5, 0x0b2f: 0x2c06, + 0x0b30: 0x2abe, 0x0b31: 0x2ab4, 0x0b32: 0x2f33, 0x0b33: 0x2c13, 0x0b34: 0x2e08, 0x0b35: 0x2ac8, + 0x0b36: 0x2d21, 0x0b37: 0x2ad2, 0x0b38: 0x2c2d, 0x0b39: 0x2adc, 0x0b3a: 0x2c3a, 0x0b3b: 0x2efd, + 0x0b3c: 0x2c20, 0x0b3d: 0x2d31, 0x0b3e: 0x2c47, 0x0b3f: 0x2886, + // Block 0x2d, offset 0xb40 + 0x0b40: 0x2f0e, 0x0b41: 0x2ae6, 0x0b42: 0x2af0, 0x0b43: 0x2c54, 0x0b44: 0x2afa, 0x0b45: 0x2b04, + 0x0b46: 0x2b0e, 0x0b47: 0x2d41, 0x0b48: 0x2c61, 0x0b49: 0x288d, 0x0b4a: 0x2e1b, 0x0b4b: 0x2ea6, + 0x0b4c: 0x2d51, 0x0b4d: 0x2c6e, 0x0b4e: 0x2ecd, 0x0b4f: 0x2b18, 0x0b50: 0x2b22, 0x0b51: 0x2c7b, + 0x0b52: 0x2894, 0x0b53: 0x2c88, 0x0b54: 0x2d61, 0x0b55: 0x289b, 0x0b56: 0x2e2e, 0x0b57: 0x2b2c, + 0x0b58: 0x1df6, 0x0b59: 0x1e0a, 0x0b5a: 0x1e19, 0x0b5b: 0x1e28, 0x0b5c: 0x1e37, 0x0b5d: 0x1e46, + 0x0b5e: 0x1e55, 0x0b5f: 0x1e64, 0x0b60: 0x1e73, 0x0b61: 0x1e82, 0x0b62: 0x22d1, 0x0b63: 0x22e3, + 0x0b64: 0x22f5, 0x0b65: 0x2301, 0x0b66: 0x230d, 0x0b67: 0x2319, 0x0b68: 0x2325, 0x0b69: 0x2331, + 0x0b6a: 0x233d, 0x0b6b: 0x2349, 0x0b6c: 0x2385, 0x0b6d: 0x2391, 0x0b6e: 0x239d, 0x0b6f: 0x23a9, + 0x0b70: 0x23b5, 0x0b71: 0x1d53, 0x0b72: 0x1b05, 0x0b73: 0x1a75, 0x0b74: 0x1d23, 0x0b75: 0x1b86, + 0x0b76: 0x1b95, 0x0b77: 0x1b0b, 0x0b78: 0x1d3b, 0x0b79: 0x1d3f, 0x0b7a: 0x1a9f, 0x0b7b: 0x28a9, + 0x0b7c: 0x28b7, 0x0b7d: 0x28a2, 0x0b7e: 0x28b0, 0x0b7f: 0x2c95, + // Block 0x2e, offset 0xb80 + 0x0b80: 0x1b89, 0x0b81: 0x1b71, 0x0b82: 0x1d9f, 0x0b83: 0x1b59, 0x0b84: 0x1b32, 0x0b85: 0x1aa8, + 0x0b86: 0x1ab7, 0x0b87: 0x1a87, 0x0b88: 0x1d2f, 0x0b89: 0x1e91, 0x0b8a: 0x1b8c, 0x0b8b: 0x1b74, + 0x0b8c: 0x1da3, 0x0b8d: 0x1daf, 0x0b8e: 0x1b65, 0x0b8f: 0x1b3b, 0x0b90: 0x1a96, 0x0b91: 0x1d5b, + 0x0b92: 0x1cef, 0x0b93: 0x1cdb, 0x0b94: 0x1d0b, 0x0b95: 0x1db3, 0x0b96: 0x1b68, 0x0b97: 0x1b08, + 0x0b98: 0x1b3e, 0x0b99: 0x1b1d, 0x0b9a: 0x1b80, 0x0b9b: 0x1db7, 0x0b9c: 0x1b6b, 0x0b9d: 0x1aff, + 0x0b9e: 0x1b41, 0x0b9f: 0x1d7b, 0x0ba0: 0x1d33, 0x0ba1: 0x1b53, 0x0ba2: 0x1d63, 0x0ba3: 0x1d7f, + 0x0ba4: 0x1d37, 0x0ba5: 0x1b56, 0x0ba6: 0x1d67, 0x0ba7: 0x2427, 0x0ba8: 0x243b, 0x0ba9: 0x1ad5, + 0x0baa: 0x1d5f, 0x0bab: 0x1cf3, 0x0bac: 0x1cdf, 0x0bad: 0x1d87, 0x0bae: 0x28be, 0x0baf: 0x2955, + 0x0bb0: 0x1b98, 0x0bb1: 0x1b83, 0x0bb2: 0x1dbb, 0x0bb3: 0x1b6e, 0x0bb4: 0x1b8f, 0x0bb5: 0x1b77, + 0x0bb6: 0x1da7, 0x0bb7: 0x1b5c, 0x0bb8: 0x1b35, 0x0bb9: 0x1ac0, 0x0bba: 0x1b92, 0x0bbb: 0x1b7a, + 0x0bbc: 0x1dab, 0x0bbd: 0x1b5f, 0x0bbe: 0x1b38, 0x0bbf: 0x1ac3, + // Block 0x2f, offset 0xbc0 + 0x0bc0: 0x1d6b, 0x0bc1: 0x1cf7, 0x0bc2: 0x1e8c, 0x0bc3: 0x1a78, 0x0bc4: 0x1af9, 0x0bc5: 0x1afc, + 0x0bc6: 0x2434, 0x0bc7: 0x1cd3, 0x0bc8: 0x1b02, 0x0bc9: 0x1a8a, 0x0bca: 0x1b20, 0x0bcb: 0x1a8d, + 0x0bcc: 0x1b29, 0x0bcd: 0x1aab, 0x0bce: 0x1aae, 0x0bcf: 0x1b44, 0x0bd0: 0x1b4a, 0x0bd1: 0x1b4d, + 0x0bd2: 0x1d6f, 0x0bd3: 0x1b50, 0x0bd4: 0x1b62, 0x0bd5: 0x1d77, 0x0bd6: 0x1d83, 0x0bd7: 0x1acf, + 0x0bd8: 0x1e96, 0x0bd9: 0x1cfb, 0x0bda: 0x1ad2, 0x0bdb: 0x1b9b, 0x0bdc: 0x1ae4, 0x0bdd: 0x1af3, + 0x0bde: 0x2421, 0x0bdf: 0x241b, 0x0be0: 0x1e00, 0x0be1: 0x1e0f, 0x0be2: 0x1e1e, 0x0be3: 0x1e2d, + 0x0be4: 0x1e3c, 0x0be5: 0x1e4b, 0x0be6: 0x1e5a, 0x0be7: 0x1e69, 0x0be8: 0x1e78, 0x0be9: 0x22c5, + 0x0bea: 0x22d7, 0x0beb: 0x22e9, 0x0bec: 0x22fb, 0x0bed: 0x2307, 0x0bee: 0x2313, 0x0bef: 0x231f, + 0x0bf0: 0x232b, 0x0bf1: 0x2337, 0x0bf2: 0x2343, 0x0bf3: 0x237f, 0x0bf4: 0x238b, 0x0bf5: 0x2397, + 0x0bf6: 0x23a3, 0x0bf7: 0x23af, 0x0bf8: 0x23bb, 0x0bf9: 0x23c1, 0x0bfa: 0x23c7, 0x0bfb: 0x23cd, + 0x0bfc: 0x23d3, 0x0bfd: 0x23e5, 0x0bfe: 0x23eb, 0x0bff: 0x1d4f, + // Block 0x30, offset 0xc00 + 0x0c00: 0x13e6, 0x0c01: 0x0d6a, 0x0c02: 0x1442, 0x0c03: 0x140e, 0x0c04: 0x0ec6, 0x0c05: 0x075a, + 0x0c06: 0x094e, 0x0c07: 0x1696, 0x0c08: 0x1696, 0x0c09: 0x0a7a, 0x0c0a: 0x14ca, 0x0c0b: 0x09b2, + 0x0c0c: 0x0a76, 0x0c0d: 0x0c5e, 0x0c0e: 0x103e, 0x0c0f: 0x11ce, 0x0c10: 0x1306, 0x0c11: 0x1342, + 0x0c12: 0x1376, 0x0c13: 0x148a, 0x0c14: 0x0de2, 0x0c15: 0x0e6e, 0x0c16: 0x0f1a, 0x0c17: 0x0fb2, + 0x0c18: 0x12ce, 0x0c19: 0x14b2, 0x0c1a: 0x15de, 0x0c1b: 0x077e, 0x0c1c: 0x0922, 0x0c1d: 0x0df6, + 0x0c1e: 0x0f3e, 0x0c1f: 0x1302, 0x0c20: 0x162e, 0x0c21: 0x0b22, 0x0c22: 0x0ee6, 0x0c23: 0x12f2, + 0x0c24: 0x1386, 0x0c25: 0x0c92, 0x0c26: 0x122a, 0x0c27: 0x134e, 0x0c28: 0x0b8e, 0x0c29: 0x0d7e, + 0x0c2a: 0x0e86, 0x0c2b: 0x0f8a, 0x0c2c: 0x1496, 0x0c2d: 0x07be, 0x0c2e: 0x0856, 0x0c2f: 0x08c2, + 0x0c30: 0x0cfa, 0x0c31: 0x0dee, 0x0c32: 0x0f3a, 0x0c33: 0x105e, 0x0c34: 0x11e6, 0x0c35: 0x12fa, + 0x0c36: 0x1312, 0x0c37: 0x1436, 0x0c38: 0x155a, 0x0c39: 0x160e, 0x0c3a: 0x162a, 0x0c3b: 0x109a, + 0x0c3c: 0x10da, 0x0c3d: 0x1192, 0x0c3e: 0x12b2, 0x0c3f: 0x14e6, + // Block 0x31, offset 0xc40 + 0x0c40: 0x1636, 0x0c41: 0x13ba, 0x0c42: 0x0a36, 0x0c43: 0x0baa, 0x0c44: 0x114a, 0x0c45: 0x120a, + 0x0c46: 0x0f6e, 0x0c47: 0x10a2, 0x0c48: 0x1406, 0x0c49: 0x1552, 0x0c4a: 0x0a32, 0x0c4b: 0x0afe, + 0x0c4c: 0x0de6, 0x0c4d: 0x0e9a, 0x0c4e: 0x0ece, 0x0c4f: 0x1182, 0x0c50: 0x11aa, 0x0c51: 0x1512, + 0x0c52: 0x08be, 0x0c53: 0x1216, 0x0c54: 0x0862, 0x0c55: 0x085e, 0x0c56: 0x1106, 0x0c57: 0x1196, + 0x0c58: 0x12ca, 0x0c59: 0x151a, 0x0c5a: 0x13d6, 0x0c5b: 0x0c96, 0x0c5c: 0x0de2, 0x0c5d: 0x13c6, + 0x0c5e: 0x0766, 0x0c5f: 0x0ad2, 0x0c60: 0x0c02, 0x0c61: 0x0f9e, 0x0c62: 0x101e, 0x0c63: 0x08e2, + 0x0c64: 0x10aa, 0x0c65: 0x07ce, 0x0c66: 0x0be6, 0x0c67: 0x0746, 0x0c68: 0x0e5a, 0x0c69: 0x0d12, + 0x0c6a: 0x117e, 0x0c6b: 0x0936, 0x0c6c: 0x0a22, 0x0c6d: 0x106a, 0x0c6e: 0x12d2, 0x0c6f: 0x13aa, + 0x0c70: 0x0e26, 0x0c71: 0x1466, 0x0c72: 0x0e52, 0x0c73: 0x0ca6, 0x0c74: 0x128a, 0x0c75: 0x0cc6, + 0x0c76: 0x101a, 0x0c77: 0x079a, 0x0c78: 0x0816, 0x0c79: 0x085a, 0x0c7a: 0x0dc2, 0x0c7b: 0x116a, + 0x0c7c: 0x1262, 0x0c7d: 0x13b6, 0x0c7e: 0x14c6, 0x0c7f: 0x08ca, + // Block 0x32, offset 0xc80 + 0x0c80: 0x097e, 0x0c81: 0x0a86, 0x0c82: 0x0b9e, 0x0c83: 0x0d2e, 0x0c84: 0x0eea, 0x0c85: 0x10ae, + 0x0c86: 0x1502, 0x0c87: 0x15e6, 0x0c88: 0x163a, 0x0c89: 0x1652, 0x0c8a: 0x08a6, 0x0c8b: 0x0d62, + 0x0c8c: 0x0e12, 0x0c8d: 0x145a, 0x0c8e: 0x0b6a, 0x0c8f: 0x0c46, 0x0c90: 0x0c62, 0x0c91: 0x0cf2, + 0x0c92: 0x0eda, 0x0c93: 0x0f26, 0x0c94: 0x0fd6, 0x0c95: 0x10fa, 0x0c96: 0x119e, 0x0c97: 0x1202, + 0x0c98: 0x144a, 0x0c99: 0x12da, 0x0c9a: 0x1472, 0x0c9b: 0x14ea, 0x0c9c: 0x087e, 0x0c9d: 0x08aa, + 0x0c9e: 0x0992, 0x0c9f: 0x0f16, 0x0ca0: 0x1362, 0x0ca1: 0x13aa, 0x0ca2: 0x0b8a, 0x0ca3: 0x0bfa, + 0x0ca4: 0x0cbe, 0x0ca5: 0x0e1e, 0x0ca6: 0x1146, 0x0ca7: 0x0f92, 0x0ca8: 0x07aa, 0x0ca9: 0x09ee, + 0x0caa: 0x0ad2, 0x0cab: 0x0b36, 0x0cac: 0x0c06, 0x0cad: 0x0fae, 0x0cae: 0x0fca, 0x0caf: 0x11da, + 0x0cb0: 0x11fa, 0x0cb1: 0x14ce, 0x0cb2: 0x154e, 0x0cb3: 0x155e, 0x0cb4: 0x159a, 0x0cb5: 0x07c2, + 0x0cb6: 0x10ee, 0x0cb7: 0x14ba, 0x0cb8: 0x1536, 0x0cb9: 0x0c1e, 0x0cba: 0x0786, 0x0cbb: 0x07e6, + 0x0cbc: 0x0ad6, 0x0cbd: 0x0af6, 0x0cbe: 0x0d1e, 0x0cbf: 0x0de2, + // Block 0x33, offset 0xcc0 + 0x0cc0: 0x0f32, 0x0cc1: 0x103a, 0x0cc2: 0x12e6, 0x0cc3: 0x1486, 0x0cc4: 0x168e, 0x0cc5: 0x0d52, + 0x0cc6: 0x150e, 0x0cc7: 0x08a2, 0x0cc8: 0x0d9e, 0x0cc9: 0x0daa, 0x0cca: 0x0e7e, 0x0ccb: 0x0eb6, + 0x0ccc: 0x0fba, 0x0ccd: 0x1016, 0x0cce: 0x1096, 0x0ccf: 0x117a, 0x0cd0: 0x15a6, 0x0cd1: 0x081e, + 0x0cd2: 0x0c72, 0x0cd3: 0x151e, 0x0cd4: 0x07d6, 0x0cd5: 0x0b1a, 0x0cd6: 0x0e9e, 0x0cd7: 0x144e, + 0x0cd8: 0x0bd6, 0x0cd9: 0x0c26, 0x0cda: 0x0db2, 0x0cdb: 0x0f9e, 0x0cdc: 0x1526, 0x0cdd: 0x0886, + 0x0cde: 0x096e, 0x0cdf: 0x0b06, 0x0ce0: 0x0d42, 0x0ce1: 0x0d8e, 0x0ce2: 0x0dce, 0x0ce3: 0x0e62, + 0x0ce4: 0x0fb6, 0x0ce5: 0x102a, 0x0ce6: 0x11c6, 0x0ce7: 0x1366, 0x0ce8: 0x1372, 0x0ce9: 0x14c2, + 0x0cea: 0x1542, 0x0ceb: 0x08f2, 0x0cec: 0x0eba, 0x0ced: 0x0972, 0x0cee: 0x0f36, 0x0cef: 0x0fda, + 0x0cf0: 0x12f6, 0x0cf1: 0x152a, 0x0cf2: 0x1616, 0x0cf3: 0x163e, 0x0cf4: 0x0da6, 0x0cf5: 0x0e96, + 0x0cf6: 0x1232, 0x0cf7: 0x1126, 0x0cf8: 0x1132, 0x0cf9: 0x1156, 0x0cfa: 0x0f86, 0x0cfb: 0x0f0e, + 0x0cfc: 0x13d2, 0x0cfd: 0x07a2, 0x0cfe: 0x129a, 0x0cff: 0x088a, + // Block 0x34, offset 0xd00 + 0x0d00: 0x087a, 0x0d01: 0x0b7a, 0x0d02: 0x0c9a, 0x0d03: 0x1162, 0x0d04: 0x0ac2, 0x0d05: 0x0e72, + 0x0d06: 0x0d5e, 0x0d07: 0x1456, 0x0d08: 0x1356, 0x0d09: 0x1516, 0x0d0a: 0x1392, 0x0d0b: 0x0b96, + 0x0d0c: 0x07f6, 0x0d0d: 0x09ca, 0x0d10: 0x0a1e, + 0x0d12: 0x0d4e, 0x0d15: 0x0866, 0x0d16: 0x0f8e, 0x0d17: 0x1052, + 0x0d18: 0x10b6, 0x0d19: 0x10d2, 0x0d1a: 0x10d6, 0x0d1b: 0x10ea, 0x0d1c: 0x1566, 0x0d1d: 0x115a, + 0x0d1e: 0x11de, 0x0d20: 0x12fe, 0x0d22: 0x13c2, + 0x0d25: 0x1476, 0x0d26: 0x14a2, + 0x0d2a: 0x15ba, 0x0d2b: 0x15be, 0x0d2c: 0x15c2, 0x0d2d: 0x1626, 0x0d2e: 0x149a, 0x0d2f: 0x1532, + 0x0d30: 0x07c6, 0x0d31: 0x07ea, 0x0d32: 0x07fe, 0x0d33: 0x08ba, 0x0d34: 0x08c6, 0x0d35: 0x0906, + 0x0d36: 0x09ba, 0x0d37: 0x09d6, 0x0d38: 0x09de, 0x0d39: 0x0a1a, 0x0d3a: 0x0a26, 0x0d3b: 0x0b02, + 0x0d3c: 0x0b0a, 0x0d3d: 0x0c12, 0x0d3e: 0x0c3a, 0x0d3f: 0x0c42, + // Block 0x35, offset 0xd40 + 0x0d40: 0x0c5a, 0x0d41: 0x0d06, 0x0d42: 0x0d36, 0x0d43: 0x0d56, 0x0d44: 0x0dc6, 0x0d45: 0x0e8a, + 0x0d46: 0x0ea6, 0x0d47: 0x0ed6, 0x0d48: 0x0f2a, 0x0d49: 0x0f4a, 0x0d4a: 0x0fbe, 0x0d4b: 0x109e, + 0x0d4c: 0x10ba, 0x0d4d: 0x10c2, 0x0d4e: 0x10be, 0x0d4f: 0x10c6, 0x0d50: 0x10ca, 0x0d51: 0x10ce, + 0x0d52: 0x10e2, 0x0d53: 0x10e6, 0x0d54: 0x110a, 0x0d55: 0x111e, 0x0d56: 0x113a, 0x0d57: 0x119e, + 0x0d58: 0x11a6, 0x0d59: 0x11ae, 0x0d5a: 0x11c2, 0x0d5b: 0x11ea, 0x0d5c: 0x123a, 0x0d5d: 0x126e, + 0x0d5e: 0x126e, 0x0d5f: 0x12d6, 0x0d60: 0x137e, 0x0d61: 0x1396, 0x0d62: 0x13ca, 0x0d63: 0x13ce, + 0x0d64: 0x1412, 0x0d65: 0x1416, 0x0d66: 0x146e, 0x0d67: 0x1476, 0x0d68: 0x1546, 0x0d69: 0x158a, + 0x0d6a: 0x15a2, 0x0d6b: 0x0c0a, 0x0d6c: 0x177d, 0x0d6d: 0x1252, + 0x0d70: 0x074e, 0x0d71: 0x0852, 0x0d72: 0x0812, 0x0d73: 0x07ba, 0x0d74: 0x07fa, 0x0d75: 0x0826, + 0x0d76: 0x08b6, 0x0d77: 0x08d2, 0x0d78: 0x09ba, 0x0d79: 0x09a6, 0x0d7a: 0x09b6, 0x0d7b: 0x09d2, + 0x0d7c: 0x0a1e, 0x0d7d: 0x0a2e, 0x0d7e: 0x0a72, 0x0d7f: 0x0a7e, + // Block 0x36, offset 0xd80 + 0x0d80: 0x0a9a, 0x0d81: 0x0aaa, 0x0d82: 0x0b92, 0x0d83: 0x0b9a, 0x0d84: 0x0bca, 0x0d85: 0x0bea, + 0x0d86: 0x0c1a, 0x0d87: 0x0c32, 0x0d88: 0x0c22, 0x0d89: 0x0c42, 0x0d8a: 0x0c36, 0x0d8b: 0x0c5a, + 0x0d8c: 0x0c76, 0x0d8d: 0x0cce, 0x0d8e: 0x0cda, 0x0d8f: 0x0ce2, 0x0d90: 0x0d0a, 0x0d91: 0x0d4e, + 0x0d92: 0x0d7e, 0x0d93: 0x0d82, 0x0d94: 0x0d96, 0x0d95: 0x0e16, 0x0d96: 0x0e26, 0x0d97: 0x0e7e, + 0x0d98: 0x0eca, 0x0d99: 0x0ec2, 0x0d9a: 0x0ed6, 0x0d9b: 0x0ef2, 0x0d9c: 0x0f2a, 0x0d9d: 0x1082, + 0x0d9e: 0x0f4e, 0x0d9f: 0x0f82, 0x0da0: 0x0f8e, 0x0da1: 0x0fce, 0x0da2: 0x0fea, 0x0da3: 0x100e, + 0x0da4: 0x1032, 0x0da5: 0x1036, 0x0da6: 0x1052, 0x0da7: 0x1056, 0x0da8: 0x1066, 0x0da9: 0x107a, + 0x0daa: 0x1076, 0x0dab: 0x10a6, 0x0dac: 0x1122, 0x0dad: 0x113a, 0x0dae: 0x1152, 0x0daf: 0x118a, + 0x0db0: 0x119e, 0x0db1: 0x11ba, 0x0db2: 0x11ea, 0x0db3: 0x129e, 0x0db4: 0x12c6, 0x0db5: 0x133a, + 0x0db6: 0x1382, 0x0db7: 0x138e, 0x0db8: 0x1396, 0x0db9: 0x13ae, 0x0dba: 0x13c2, 0x0dbb: 0x13b2, + 0x0dbc: 0x13ca, 0x0dbd: 0x13c6, 0x0dbe: 0x13be, 0x0dbf: 0x13ce, + // Block 0x37, offset 0xdc0 + 0x0dc0: 0x13da, 0x0dc1: 0x1416, 0x0dc2: 0x1452, 0x0dc3: 0x1482, 0x0dc4: 0x14b6, 0x0dc5: 0x14d6, + 0x0dc6: 0x1522, 0x0dc7: 0x1546, 0x0dc8: 0x1566, 0x0dc9: 0x157a, 0x0dca: 0x158a, 0x0dcb: 0x1596, + 0x0dcc: 0x15a2, 0x0dcd: 0x15f6, 0x0dce: 0x1696, 0x0dcf: 0x1714, 0x0dd0: 0x170f, 0x0dd1: 0x1741, + 0x0dd2: 0x0676, 0x0dd3: 0x069e, 0x0dd4: 0x06a2, 0x0dd5: 0x17c3, 0x0dd6: 0x17f0, 0x0dd7: 0x1868, + 0x0dd8: 0x1682, 0x0dd9: 0x1692, + // Block 0x38, offset 0xe00 + 0x0e00: 0x1b14, 0x0e01: 0x1b17, 0x0e02: 0x1b1a, 0x0e03: 0x1d47, 0x0e04: 0x1d4b, 0x0e05: 0x1b9e, + 0x0e06: 0x1b9e, + 0x0e13: 0x1eb4, 0x0e14: 0x1ea5, 0x0e15: 0x1eaa, 0x0e16: 0x1eb9, 0x0e17: 0x1eaf, + 0x0e1d: 0x4377, + 0x0e1e: 0x8115, 0x0e1f: 0x43e9, 0x0e20: 0x0224, 0x0e21: 0x020c, 0x0e22: 0x0215, 0x0e23: 0x0218, + 0x0e24: 0x021b, 0x0e25: 0x021e, 0x0e26: 0x0221, 0x0e27: 0x0227, 0x0e28: 0x022a, 0x0e29: 0x0017, + 0x0e2a: 0x43d7, 0x0e2b: 0x43dd, 0x0e2c: 0x44db, 0x0e2d: 0x44e3, 0x0e2e: 0x432f, 0x0e2f: 0x4335, + 0x0e30: 0x433b, 0x0e31: 0x4341, 0x0e32: 0x434d, 0x0e33: 0x4353, 0x0e34: 0x4359, 0x0e35: 0x4365, + 0x0e36: 0x436b, 0x0e38: 0x4371, 0x0e39: 0x437d, 0x0e3a: 0x4383, 0x0e3b: 0x4389, + 0x0e3c: 0x4395, 0x0e3e: 0x439b, + // Block 0x39, offset 0xe40 + 0x0e40: 0x43a1, 0x0e41: 0x43a7, 0x0e43: 0x43ad, 0x0e44: 0x43b3, + 0x0e46: 0x43bf, 0x0e47: 0x43c5, 0x0e48: 0x43cb, 0x0e49: 0x43d1, 0x0e4a: 0x43e3, 0x0e4b: 0x435f, + 0x0e4c: 0x4347, 0x0e4d: 0x438f, 0x0e4e: 0x43b9, 0x0e4f: 0x1ebe, 0x0e50: 0x0290, 0x0e51: 0x0290, + 0x0e52: 0x0299, 0x0e53: 0x0299, 0x0e54: 0x0299, 0x0e55: 0x0299, 0x0e56: 0x029c, 0x0e57: 0x029c, + 0x0e58: 0x029c, 0x0e59: 0x029c, 0x0e5a: 0x02a2, 0x0e5b: 0x02a2, 0x0e5c: 0x02a2, 0x0e5d: 0x02a2, + 0x0e5e: 0x0296, 0x0e5f: 0x0296, 0x0e60: 0x0296, 0x0e61: 0x0296, 0x0e62: 0x029f, 0x0e63: 0x029f, + 0x0e64: 0x029f, 0x0e65: 0x029f, 0x0e66: 0x0293, 0x0e67: 0x0293, 0x0e68: 0x0293, 0x0e69: 0x0293, + 0x0e6a: 0x02c6, 0x0e6b: 0x02c6, 0x0e6c: 0x02c6, 0x0e6d: 0x02c6, 0x0e6e: 0x02c9, 0x0e6f: 0x02c9, + 0x0e70: 0x02c9, 0x0e71: 0x02c9, 0x0e72: 0x02a8, 0x0e73: 0x02a8, 0x0e74: 0x02a8, 0x0e75: 0x02a8, + 0x0e76: 0x02a5, 0x0e77: 0x02a5, 0x0e78: 0x02a5, 0x0e79: 0x02a5, 0x0e7a: 0x02ab, 0x0e7b: 0x02ab, + 0x0e7c: 0x02ab, 0x0e7d: 0x02ab, 0x0e7e: 0x02ae, 0x0e7f: 0x02ae, + // Block 0x3a, offset 0xe80 + 0x0e80: 0x02ae, 0x0e81: 0x02ae, 0x0e82: 0x02b7, 0x0e83: 0x02b7, 0x0e84: 0x02b4, 0x0e85: 0x02b4, + 0x0e86: 0x02ba, 0x0e87: 0x02ba, 0x0e88: 0x02b1, 0x0e89: 0x02b1, 0x0e8a: 0x02c0, 0x0e8b: 0x02c0, + 0x0e8c: 0x02bd, 0x0e8d: 0x02bd, 0x0e8e: 0x02cc, 0x0e8f: 0x02cc, 0x0e90: 0x02cc, 0x0e91: 0x02cc, + 0x0e92: 0x02d2, 0x0e93: 0x02d2, 0x0e94: 0x02d2, 0x0e95: 0x02d2, 0x0e96: 0x02d8, 0x0e97: 0x02d8, + 0x0e98: 0x02d8, 0x0e99: 0x02d8, 0x0e9a: 0x02d5, 0x0e9b: 0x02d5, 0x0e9c: 0x02d5, 0x0e9d: 0x02d5, + 0x0e9e: 0x02db, 0x0e9f: 0x02db, 0x0ea0: 0x02de, 0x0ea1: 0x02de, 0x0ea2: 0x02de, 0x0ea3: 0x02de, + 0x0ea4: 0x4455, 0x0ea5: 0x4455, 0x0ea6: 0x02e4, 0x0ea7: 0x02e4, 0x0ea8: 0x02e4, 0x0ea9: 0x02e4, + 0x0eaa: 0x02e1, 0x0eab: 0x02e1, 0x0eac: 0x02e1, 0x0ead: 0x02e1, 0x0eae: 0x02ff, 0x0eaf: 0x02ff, + 0x0eb0: 0x444f, 0x0eb1: 0x444f, + // Block 0x3b, offset 0xec0 + 0x0ed3: 0x02cf, 0x0ed4: 0x02cf, 0x0ed5: 0x02cf, 0x0ed6: 0x02cf, 0x0ed7: 0x02ed, + 0x0ed8: 0x02ed, 0x0ed9: 0x02ea, 0x0eda: 0x02ea, 0x0edb: 0x02f0, 0x0edc: 0x02f0, 0x0edd: 0x218e, + 0x0ede: 0x02f6, 0x0edf: 0x02f6, 0x0ee0: 0x02e7, 0x0ee1: 0x02e7, 0x0ee2: 0x02f3, 0x0ee3: 0x02f3, + 0x0ee4: 0x02fc, 0x0ee5: 0x02fc, 0x0ee6: 0x02fc, 0x0ee7: 0x02fc, 0x0ee8: 0x0284, 0x0ee9: 0x0284, + 0x0eea: 0x26e9, 0x0eeb: 0x26e9, 0x0eec: 0x2759, 0x0eed: 0x2759, 0x0eee: 0x2728, 0x0eef: 0x2728, + 0x0ef0: 0x2744, 0x0ef1: 0x2744, 0x0ef2: 0x273d, 0x0ef3: 0x273d, 0x0ef4: 0x274b, 0x0ef5: 0x274b, + 0x0ef6: 0x2752, 0x0ef7: 0x2752, 0x0ef8: 0x2752, 0x0ef9: 0x272f, 0x0efa: 0x272f, 0x0efb: 0x272f, + 0x0efc: 0x02f9, 0x0efd: 0x02f9, 0x0efe: 0x02f9, 0x0eff: 0x02f9, + // Block 0x3c, offset 0xf00 + 0x0f00: 0x26f0, 0x0f01: 0x26f7, 0x0f02: 0x2713, 0x0f03: 0x272f, 0x0f04: 0x2736, 0x0f05: 0x1ec8, + 0x0f06: 0x1ecd, 0x0f07: 0x1ed2, 0x0f08: 0x1ee1, 0x0f09: 0x1ef0, 0x0f0a: 0x1ef5, 0x0f0b: 0x1efa, + 0x0f0c: 0x1eff, 0x0f0d: 0x1f04, 0x0f0e: 0x1f13, 0x0f0f: 0x1f22, 0x0f10: 0x1f27, 0x0f11: 0x1f2c, + 0x0f12: 0x1f3b, 0x0f13: 0x1f4a, 0x0f14: 0x1f4f, 0x0f15: 0x1f54, 0x0f16: 0x1f59, 0x0f17: 0x1f68, + 0x0f18: 0x1f6d, 0x0f19: 0x1f7c, 0x0f1a: 0x1f81, 0x0f1b: 0x1f86, 0x0f1c: 0x1f95, 0x0f1d: 0x1f9a, + 0x0f1e: 0x1f9f, 0x0f1f: 0x1fa9, 0x0f20: 0x1fe5, 0x0f21: 0x1ff4, 0x0f22: 0x2003, 0x0f23: 0x2008, + 0x0f24: 0x200d, 0x0f25: 0x2017, 0x0f26: 0x2026, 0x0f27: 0x202b, 0x0f28: 0x203a, 0x0f29: 0x203f, + 0x0f2a: 0x2044, 0x0f2b: 0x2053, 0x0f2c: 0x2058, 0x0f2d: 0x2067, 0x0f2e: 0x206c, 0x0f2f: 0x2071, + 0x0f30: 0x2076, 0x0f31: 0x207b, 0x0f32: 0x2080, 0x0f33: 0x2085, 0x0f34: 0x208a, 0x0f35: 0x208f, + 0x0f36: 0x2094, 0x0f37: 0x2099, 0x0f38: 0x209e, 0x0f39: 0x20a3, 0x0f3a: 0x20a8, 0x0f3b: 0x20ad, + 0x0f3c: 0x20b2, 0x0f3d: 0x20b7, 0x0f3e: 0x20bc, 0x0f3f: 0x20c6, + // Block 0x3d, offset 0xf40 + 0x0f40: 0x20cb, 0x0f41: 0x20d0, 0x0f42: 0x20d5, 0x0f43: 0x20df, 0x0f44: 0x20e4, 0x0f45: 0x20ee, + 0x0f46: 0x20f3, 0x0f47: 0x20f8, 0x0f48: 0x20fd, 0x0f49: 0x2102, 0x0f4a: 0x2107, 0x0f4b: 0x210c, + 0x0f4c: 0x2111, 0x0f4d: 0x2116, 0x0f4e: 0x2125, 0x0f4f: 0x2134, 0x0f50: 0x2139, 0x0f51: 0x213e, + 0x0f52: 0x2143, 0x0f53: 0x2148, 0x0f54: 0x214d, 0x0f55: 0x2157, 0x0f56: 0x215c, 0x0f57: 0x2161, + 0x0f58: 0x2170, 0x0f59: 0x217f, 0x0f5a: 0x2184, 0x0f5b: 0x4407, 0x0f5c: 0x440d, 0x0f5d: 0x4443, + 0x0f5e: 0x449a, 0x0f5f: 0x44a1, 0x0f60: 0x44a8, 0x0f61: 0x44af, 0x0f62: 0x44b6, 0x0f63: 0x44bd, + 0x0f64: 0x2705, 0x0f65: 0x270c, 0x0f66: 0x2713, 0x0f67: 0x271a, 0x0f68: 0x272f, 0x0f69: 0x2736, + 0x0f6a: 0x1ed7, 0x0f6b: 0x1edc, 0x0f6c: 0x1ee1, 0x0f6d: 0x1ee6, 0x0f6e: 0x1ef0, 0x0f6f: 0x1ef5, + 0x0f70: 0x1f09, 0x0f71: 0x1f0e, 0x0f72: 0x1f13, 0x0f73: 0x1f18, 0x0f74: 0x1f22, 0x0f75: 0x1f27, + 0x0f76: 0x1f31, 0x0f77: 0x1f36, 0x0f78: 0x1f3b, 0x0f79: 0x1f40, 0x0f7a: 0x1f4a, 0x0f7b: 0x1f4f, + 0x0f7c: 0x207b, 0x0f7d: 0x2080, 0x0f7e: 0x208f, 0x0f7f: 0x2094, + // Block 0x3e, offset 0xf80 + 0x0f80: 0x2099, 0x0f81: 0x20ad, 0x0f82: 0x20b2, 0x0f83: 0x20b7, 0x0f84: 0x20bc, 0x0f85: 0x20d5, + 0x0f86: 0x20df, 0x0f87: 0x20e4, 0x0f88: 0x20e9, 0x0f89: 0x20fd, 0x0f8a: 0x211b, 0x0f8b: 0x2120, + 0x0f8c: 0x2125, 0x0f8d: 0x212a, 0x0f8e: 0x2134, 0x0f8f: 0x2139, 0x0f90: 0x4443, 0x0f91: 0x2166, + 0x0f92: 0x216b, 0x0f93: 0x2170, 0x0f94: 0x2175, 0x0f95: 0x217f, 0x0f96: 0x2184, 0x0f97: 0x26f0, + 0x0f98: 0x26f7, 0x0f99: 0x26fe, 0x0f9a: 0x2713, 0x0f9b: 0x2721, 0x0f9c: 0x1ec8, 0x0f9d: 0x1ecd, + 0x0f9e: 0x1ed2, 0x0f9f: 0x1ee1, 0x0fa0: 0x1eeb, 0x0fa1: 0x1efa, 0x0fa2: 0x1eff, 0x0fa3: 0x1f04, + 0x0fa4: 0x1f13, 0x0fa5: 0x1f1d, 0x0fa6: 0x1f3b, 0x0fa7: 0x1f54, 0x0fa8: 0x1f59, 0x0fa9: 0x1f68, + 0x0faa: 0x1f6d, 0x0fab: 0x1f7c, 0x0fac: 0x1f86, 0x0fad: 0x1f95, 0x0fae: 0x1f9a, 0x0faf: 0x1f9f, + 0x0fb0: 0x1fa9, 0x0fb1: 0x1fe5, 0x0fb2: 0x1fea, 0x0fb3: 0x1ff4, 0x0fb4: 0x2003, 0x0fb5: 0x2008, + 0x0fb6: 0x200d, 0x0fb7: 0x2017, 0x0fb8: 0x2026, 0x0fb9: 0x203a, 0x0fba: 0x203f, 0x0fbb: 0x2044, + 0x0fbc: 0x2053, 0x0fbd: 0x2058, 0x0fbe: 0x2067, 0x0fbf: 0x206c, + // Block 0x3f, offset 0xfc0 + 0x0fc0: 0x2071, 0x0fc1: 0x2076, 0x0fc2: 0x2085, 0x0fc3: 0x208a, 0x0fc4: 0x209e, 0x0fc5: 0x20a3, + 0x0fc6: 0x20a8, 0x0fc7: 0x20ad, 0x0fc8: 0x20b2, 0x0fc9: 0x20c6, 0x0fca: 0x20cb, 0x0fcb: 0x20d0, + 0x0fcc: 0x20d5, 0x0fcd: 0x20da, 0x0fce: 0x20ee, 0x0fcf: 0x20f3, 0x0fd0: 0x20f8, 0x0fd1: 0x20fd, + 0x0fd2: 0x210c, 0x0fd3: 0x2111, 0x0fd4: 0x2116, 0x0fd5: 0x2125, 0x0fd6: 0x212f, 0x0fd7: 0x213e, + 0x0fd8: 0x2143, 0x0fd9: 0x4437, 0x0fda: 0x2157, 0x0fdb: 0x215c, 0x0fdc: 0x2161, 0x0fdd: 0x2170, + 0x0fde: 0x217a, 0x0fdf: 0x2713, 0x0fe0: 0x2721, 0x0fe1: 0x1ee1, 0x0fe2: 0x1eeb, 0x0fe3: 0x1f13, + 0x0fe4: 0x1f1d, 0x0fe5: 0x1f3b, 0x0fe6: 0x1f45, 0x0fe7: 0x1fa9, 0x0fe8: 0x1fae, 0x0fe9: 0x1fd1, + 0x0fea: 0x1fd6, 0x0feb: 0x20ad, 0x0fec: 0x20b2, 0x0fed: 0x20d5, 0x0fee: 0x2125, 0x0fef: 0x212f, + 0x0ff0: 0x2170, 0x0ff1: 0x217a, 0x0ff2: 0x44eb, 0x0ff3: 0x44f3, 0x0ff4: 0x44fb, 0x0ff5: 0x2030, + 0x0ff6: 0x2035, 0x0ff7: 0x2049, 0x0ff8: 0x204e, 0x0ff9: 0x205d, 0x0ffa: 0x2062, 0x0ffb: 0x1fb3, + 0x0ffc: 0x1fb8, 0x0ffd: 0x1fdb, 0x0ffe: 0x1fe0, 0x0fff: 0x1f72, + // Block 0x40, offset 0x1000 + 0x1000: 0x1f77, 0x1001: 0x1f5e, 0x1002: 0x1f63, 0x1003: 0x1f8b, 0x1004: 0x1f90, 0x1005: 0x1ff9, + 0x1006: 0x1ffe, 0x1007: 0x201c, 0x1008: 0x2021, 0x1009: 0x1fbd, 0x100a: 0x1fc2, 0x100b: 0x1fc7, + 0x100c: 0x1fd1, 0x100d: 0x1fcc, 0x100e: 0x1fa4, 0x100f: 0x1fef, 0x1010: 0x2012, 0x1011: 0x2030, + 0x1012: 0x2035, 0x1013: 0x2049, 0x1014: 0x204e, 0x1015: 0x205d, 0x1016: 0x2062, 0x1017: 0x1fb3, + 0x1018: 0x1fb8, 0x1019: 0x1fdb, 0x101a: 0x1fe0, 0x101b: 0x1f72, 0x101c: 0x1f77, 0x101d: 0x1f5e, + 0x101e: 0x1f63, 0x101f: 0x1f8b, 0x1020: 0x1f90, 0x1021: 0x1ff9, 0x1022: 0x1ffe, 0x1023: 0x201c, + 0x1024: 0x2021, 0x1025: 0x1fbd, 0x1026: 0x1fc2, 0x1027: 0x1fc7, 0x1028: 0x1fd1, 0x1029: 0x1fcc, + 0x102a: 0x1fa4, 0x102b: 0x1fef, 0x102c: 0x2012, 0x102d: 0x1fbd, 0x102e: 0x1fc2, 0x102f: 0x1fc7, + 0x1030: 0x1fd1, 0x1031: 0x1fae, 0x1032: 0x1fd6, 0x1033: 0x202b, 0x1034: 0x1f95, 0x1035: 0x1f9a, + 0x1036: 0x1f9f, 0x1037: 0x1fbd, 0x1038: 0x1fc2, 0x1039: 0x1fc7, 0x103a: 0x202b, 0x103b: 0x203a, + 0x103c: 0x43ef, 0x103d: 0x43ef, + // Block 0x41, offset 0x1040 + 0x1050: 0x2450, 0x1051: 0x2465, + 0x1052: 0x2465, 0x1053: 0x246c, 0x1054: 0x2473, 0x1055: 0x2488, 0x1056: 0x248f, 0x1057: 0x2496, + 0x1058: 0x24b9, 0x1059: 0x24b9, 0x105a: 0x24dc, 0x105b: 0x24d5, 0x105c: 0x24f1, 0x105d: 0x24e3, + 0x105e: 0x24ea, 0x105f: 0x250d, 0x1060: 0x250d, 0x1061: 0x2506, 0x1062: 0x2514, 0x1063: 0x2514, + 0x1064: 0x253e, 0x1065: 0x253e, 0x1066: 0x255a, 0x1067: 0x2522, 0x1068: 0x2522, 0x1069: 0x251b, + 0x106a: 0x2530, 0x106b: 0x2530, 0x106c: 0x2537, 0x106d: 0x2537, 0x106e: 0x2561, 0x106f: 0x256f, + 0x1070: 0x256f, 0x1071: 0x2576, 0x1072: 0x2576, 0x1073: 0x257d, 0x1074: 0x2584, 0x1075: 0x258b, + 0x1076: 0x2592, 0x1077: 0x2592, 0x1078: 0x2599, 0x1079: 0x25a7, 0x107a: 0x25b5, 0x107b: 0x25ae, + 0x107c: 0x25bc, 0x107d: 0x25bc, 0x107e: 0x25d1, 0x107f: 0x25d8, + // Block 0x42, offset 0x1080 + 0x1080: 0x2609, 0x1081: 0x2617, 0x1082: 0x2610, 0x1083: 0x25f4, 0x1084: 0x25f4, 0x1085: 0x261e, + 0x1086: 0x261e, 0x1087: 0x2625, 0x1088: 0x2625, 0x1089: 0x264f, 0x108a: 0x2656, 0x108b: 0x265d, + 0x108c: 0x2633, 0x108d: 0x2641, 0x108e: 0x2664, 0x108f: 0x266b, + 0x1092: 0x263a, 0x1093: 0x26bf, 0x1094: 0x26c6, 0x1095: 0x269c, 0x1096: 0x26a3, 0x1097: 0x2687, + 0x1098: 0x2687, 0x1099: 0x268e, 0x109a: 0x26b8, 0x109b: 0x26b1, 0x109c: 0x26db, 0x109d: 0x26db, + 0x109e: 0x2449, 0x109f: 0x245e, 0x10a0: 0x2457, 0x10a1: 0x2481, 0x10a2: 0x247a, 0x10a3: 0x24a4, + 0x10a4: 0x249d, 0x10a5: 0x24c7, 0x10a6: 0x24ab, 0x10a7: 0x24c0, 0x10a8: 0x24f8, 0x10a9: 0x2545, + 0x10aa: 0x2529, 0x10ab: 0x2568, 0x10ac: 0x2602, 0x10ad: 0x262c, 0x10ae: 0x26d4, 0x10af: 0x26cd, + 0x10b0: 0x26e2, 0x10b1: 0x2679, 0x10b2: 0x25df, 0x10b3: 0x26aa, 0x10b4: 0x25d1, 0x10b5: 0x2609, + 0x10b6: 0x25a0, 0x10b7: 0x25ed, 0x10b8: 0x2680, 0x10b9: 0x2672, 0x10ba: 0x25fb, 0x10bb: 0x25e6, + 0x10bc: 0x25fb, 0x10bd: 0x2680, 0x10be: 0x24b2, 0x10bf: 0x24ce, + // Block 0x43, offset 0x10c0 + 0x10c0: 0x2648, 0x10c1: 0x25c3, 0x10c2: 0x2442, 0x10c3: 0x25e6, 0x10c4: 0x258b, 0x10c5: 0x255a, + 0x10c6: 0x24ff, 0x10c7: 0x2695, + 0x10f0: 0x2553, 0x10f1: 0x25ca, 0x10f2: 0x2967, 0x10f3: 0x295e, 0x10f4: 0x2994, 0x10f5: 0x2982, + 0x10f6: 0x2970, 0x10f7: 0x298b, 0x10f8: 0x299d, 0x10f9: 0x254c, 0x10fa: 0x2e41, 0x10fb: 0x2cb1, + 0x10fc: 0x2979, + // Block 0x44, offset 0x1100 + 0x1110: 0x0019, 0x1111: 0x04f2, + 0x1112: 0x04f6, 0x1113: 0x0035, 0x1114: 0x0037, 0x1115: 0x0003, 0x1116: 0x003f, 0x1117: 0x052e, + 0x1118: 0x0532, 0x1119: 0x1c9b, + 0x1120: 0x8132, 0x1121: 0x8132, 0x1122: 0x8132, 0x1123: 0x8132, + 0x1124: 0x8132, 0x1125: 0x8132, 0x1126: 0x8132, + 0x1130: 0x19b2, 0x1131: 0x04b2, 0x1132: 0x04ae, 0x1133: 0x007f, 0x1134: 0x007f, 0x1135: 0x0011, + 0x1136: 0x0013, 0x1137: 0x00b7, 0x1138: 0x00bb, 0x1139: 0x0526, 0x113a: 0x052a, 0x113b: 0x051a, + 0x113c: 0x051e, 0x113d: 0x0502, 0x113e: 0x0506, 0x113f: 0x04fa, + // Block 0x45, offset 0x1140 + 0x1140: 0x04fe, 0x1141: 0x050a, 0x1142: 0x050e, 0x1143: 0x0512, 0x1144: 0x0516, + 0x1147: 0x0077, 0x1148: 0x007b, 0x1149: 0x4250, 0x114a: 0x4250, 0x114b: 0x4250, + 0x114c: 0x4250, 0x114d: 0x007f, 0x114e: 0x007f, 0x114f: 0x007f, 0x1150: 0x0019, 0x1151: 0x04f2, + 0x1152: 0x001d, 0x1154: 0x0037, 0x1155: 0x0035, 0x1156: 0x003f, 0x1157: 0x0003, + 0x1158: 0x04b2, 0x1159: 0x0011, 0x115a: 0x0013, 0x115b: 0x00b7, 0x115c: 0x00bb, 0x115d: 0x0526, + 0x115e: 0x052a, 0x115f: 0x0007, 0x1160: 0x000d, 0x1161: 0x0015, 0x1162: 0x0017, 0x1163: 0x001b, + 0x1164: 0x0039, 0x1165: 0x003d, 0x1166: 0x003b, 0x1168: 0x0079, 0x1169: 0x0009, + 0x116a: 0x000b, 0x116b: 0x0041, + 0x1170: 0x4291, 0x1171: 0x4413, 0x1172: 0x4296, 0x1174: 0x429b, + 0x1176: 0x42a0, 0x1177: 0x4419, 0x1178: 0x42a5, 0x1179: 0x441f, 0x117a: 0x42aa, 0x117b: 0x4425, + 0x117c: 0x42af, 0x117d: 0x442b, 0x117e: 0x42b4, 0x117f: 0x4431, + // Block 0x46, offset 0x1180 + 0x1180: 0x022d, 0x1181: 0x43f5, 0x1182: 0x43f5, 0x1183: 0x43fb, 0x1184: 0x43fb, 0x1185: 0x443d, + 0x1186: 0x443d, 0x1187: 0x4401, 0x1188: 0x4401, 0x1189: 0x4449, 0x118a: 0x4449, 0x118b: 0x4449, + 0x118c: 0x4449, 0x118d: 0x0230, 0x118e: 0x0230, 0x118f: 0x0233, 0x1190: 0x0233, 0x1191: 0x0233, + 0x1192: 0x0233, 0x1193: 0x0236, 0x1194: 0x0236, 0x1195: 0x0239, 0x1196: 0x0239, 0x1197: 0x0239, + 0x1198: 0x0239, 0x1199: 0x023c, 0x119a: 0x023c, 0x119b: 0x023c, 0x119c: 0x023c, 0x119d: 0x023f, + 0x119e: 0x023f, 0x119f: 0x023f, 0x11a0: 0x023f, 0x11a1: 0x0242, 0x11a2: 0x0242, 0x11a3: 0x0242, + 0x11a4: 0x0242, 0x11a5: 0x0245, 0x11a6: 0x0245, 0x11a7: 0x0245, 0x11a8: 0x0245, 0x11a9: 0x0248, + 0x11aa: 0x0248, 0x11ab: 0x024b, 0x11ac: 0x024b, 0x11ad: 0x024e, 0x11ae: 0x024e, 0x11af: 0x0251, + 0x11b0: 0x0251, 0x11b1: 0x0254, 0x11b2: 0x0254, 0x11b3: 0x0254, 0x11b4: 0x0254, 0x11b5: 0x0257, + 0x11b6: 0x0257, 0x11b7: 0x0257, 0x11b8: 0x0257, 0x11b9: 0x025a, 0x11ba: 0x025a, 0x11bb: 0x025a, + 0x11bc: 0x025a, 0x11bd: 0x025d, 0x11be: 0x025d, 0x11bf: 0x025d, + // Block 0x47, offset 0x11c0 + 0x11c0: 0x025d, 0x11c1: 0x0260, 0x11c2: 0x0260, 0x11c3: 0x0260, 0x11c4: 0x0260, 0x11c5: 0x0263, + 0x11c6: 0x0263, 0x11c7: 0x0263, 0x11c8: 0x0263, 0x11c9: 0x0266, 0x11ca: 0x0266, 0x11cb: 0x0266, + 0x11cc: 0x0266, 0x11cd: 0x0269, 0x11ce: 0x0269, 0x11cf: 0x0269, 0x11d0: 0x0269, 0x11d1: 0x026c, + 0x11d2: 0x026c, 0x11d3: 0x026c, 0x11d4: 0x026c, 0x11d5: 0x026f, 0x11d6: 0x026f, 0x11d7: 0x026f, + 0x11d8: 0x026f, 0x11d9: 0x0272, 0x11da: 0x0272, 0x11db: 0x0272, 0x11dc: 0x0272, 0x11dd: 0x0275, + 0x11de: 0x0275, 0x11df: 0x0275, 0x11e0: 0x0275, 0x11e1: 0x0278, 0x11e2: 0x0278, 0x11e3: 0x0278, + 0x11e4: 0x0278, 0x11e5: 0x027b, 0x11e6: 0x027b, 0x11e7: 0x027b, 0x11e8: 0x027b, 0x11e9: 0x027e, + 0x11ea: 0x027e, 0x11eb: 0x027e, 0x11ec: 0x027e, 0x11ed: 0x0281, 0x11ee: 0x0281, 0x11ef: 0x0284, + 0x11f0: 0x0284, 0x11f1: 0x0287, 0x11f2: 0x0287, 0x11f3: 0x0287, 0x11f4: 0x0287, 0x11f5: 0x2e8e, + 0x11f6: 0x2e8e, 0x11f7: 0x2e96, 0x11f8: 0x2e96, 0x11f9: 0x2e9e, 0x11fa: 0x2e9e, 0x11fb: 0x20c1, + 0x11fc: 0x20c1, + // Block 0x48, offset 0x1200 + 0x1200: 0x0081, 0x1201: 0x0083, 0x1202: 0x0085, 0x1203: 0x0087, 0x1204: 0x0089, 0x1205: 0x008b, + 0x1206: 0x008d, 0x1207: 0x008f, 0x1208: 0x0091, 0x1209: 0x0093, 0x120a: 0x0095, 0x120b: 0x0097, + 0x120c: 0x0099, 0x120d: 0x009b, 0x120e: 0x009d, 0x120f: 0x009f, 0x1210: 0x00a1, 0x1211: 0x00a3, + 0x1212: 0x00a5, 0x1213: 0x00a7, 0x1214: 0x00a9, 0x1215: 0x00ab, 0x1216: 0x00ad, 0x1217: 0x00af, + 0x1218: 0x00b1, 0x1219: 0x00b3, 0x121a: 0x00b5, 0x121b: 0x00b7, 0x121c: 0x00b9, 0x121d: 0x00bb, + 0x121e: 0x00bd, 0x121f: 0x04e6, 0x1220: 0x04ea, 0x1221: 0x04f6, 0x1222: 0x050a, 0x1223: 0x050e, + 0x1224: 0x04f2, 0x1225: 0x061a, 0x1226: 0x0612, 0x1227: 0x0536, 0x1228: 0x053e, 0x1229: 0x0546, + 0x122a: 0x054e, 0x122b: 0x0556, 0x122c: 0x05da, 0x122d: 0x05e2, 0x122e: 0x05ea, 0x122f: 0x058e, + 0x1230: 0x061e, 0x1231: 0x053a, 0x1232: 0x0542, 0x1233: 0x054a, 0x1234: 0x0552, 0x1235: 0x055a, + 0x1236: 0x055e, 0x1237: 0x0562, 0x1238: 0x0566, 0x1239: 0x056a, 0x123a: 0x056e, 0x123b: 0x0572, + 0x123c: 0x0576, 0x123d: 0x057a, 0x123e: 0x057e, 0x123f: 0x0582, + // Block 0x49, offset 0x1240 + 0x1240: 0x0586, 0x1241: 0x058a, 0x1242: 0x0592, 0x1243: 0x0596, 0x1244: 0x059a, 0x1245: 0x059e, + 0x1246: 0x05a2, 0x1247: 0x05a6, 0x1248: 0x05aa, 0x1249: 0x05ae, 0x124a: 0x05b2, 0x124b: 0x05b6, + 0x124c: 0x05ba, 0x124d: 0x05be, 0x124e: 0x05c2, 0x124f: 0x05c6, 0x1250: 0x05ca, 0x1251: 0x05ce, + 0x1252: 0x05d2, 0x1253: 0x05d6, 0x1254: 0x05de, 0x1255: 0x05e6, 0x1256: 0x05ee, 0x1257: 0x05f2, + 0x1258: 0x05f6, 0x1259: 0x05fa, 0x125a: 0x05fe, 0x125b: 0x0602, 0x125c: 0x0606, 0x125d: 0x0616, + 0x125e: 0x49ab, 0x125f: 0x49b1, 0x1260: 0x03ba, 0x1261: 0x030a, 0x1262: 0x030e, 0x1263: 0x0432, + 0x1264: 0x0312, 0x1265: 0x0436, 0x1266: 0x043a, 0x1267: 0x0316, 0x1268: 0x031a, 0x1269: 0x031e, + 0x126a: 0x043e, 0x126b: 0x0442, 0x126c: 0x0446, 0x126d: 0x044a, 0x126e: 0x044e, 0x126f: 0x0452, + 0x1270: 0x035e, 0x1271: 0x0322, 0x1272: 0x0326, 0x1273: 0x032a, 0x1274: 0x0372, 0x1275: 0x032e, + 0x1276: 0x0332, 0x1277: 0x0336, 0x1278: 0x033a, 0x1279: 0x033e, 0x127a: 0x0342, 0x127b: 0x0346, + 0x127c: 0x034a, 0x127d: 0x034e, 0x127e: 0x0352, + // Block 0x4a, offset 0x1280 + 0x1280: 0x0063, 0x1281: 0x0065, 0x1282: 0x0067, 0x1283: 0x0069, 0x1284: 0x006b, 0x1285: 0x006d, + 0x1286: 0x006f, 0x1287: 0x0071, 0x1288: 0x0073, 0x1289: 0x0075, 0x128a: 0x0083, 0x128b: 0x0085, + 0x128c: 0x0087, 0x128d: 0x0089, 0x128e: 0x008b, 0x128f: 0x008d, 0x1290: 0x008f, 0x1291: 0x0091, + 0x1292: 0x0093, 0x1293: 0x0095, 0x1294: 0x0097, 0x1295: 0x0099, 0x1296: 0x009b, 0x1297: 0x009d, + 0x1298: 0x009f, 0x1299: 0x00a1, 0x129a: 0x00a3, 0x129b: 0x00a5, 0x129c: 0x00a7, 0x129d: 0x00a9, + 0x129e: 0x00ab, 0x129f: 0x00ad, 0x12a0: 0x00af, 0x12a1: 0x00b1, 0x12a2: 0x00b3, 0x12a3: 0x00b5, + 0x12a4: 0x00dd, 0x12a5: 0x00f2, 0x12a8: 0x0170, 0x12a9: 0x0173, + 0x12aa: 0x0176, 0x12ab: 0x0179, 0x12ac: 0x017c, 0x12ad: 0x017f, 0x12ae: 0x0182, 0x12af: 0x0185, + 0x12b0: 0x0188, 0x12b1: 0x018b, 0x12b2: 0x018e, 0x12b3: 0x0191, 0x12b4: 0x0194, 0x12b5: 0x0197, + 0x12b6: 0x019a, 0x12b7: 0x019d, 0x12b8: 0x01a0, 0x12b9: 0x0185, 0x12ba: 0x01a3, 0x12bb: 0x01a6, + 0x12bc: 0x01a9, 0x12bd: 0x01ac, 0x12be: 0x01af, 0x12bf: 0x01b2, + // Block 0x4b, offset 0x12c0 + 0x12c0: 0x01fa, 0x12c1: 0x01fd, 0x12c2: 0x0200, 0x12c3: 0x04ca, 0x12c4: 0x01c4, 0x12c5: 0x01cd, + 0x12c6: 0x01d3, 0x12c7: 0x01f7, 0x12c8: 0x01e8, 0x12c9: 0x01e5, 0x12ca: 0x0203, 0x12cb: 0x0206, + 0x12ce: 0x0021, 0x12cf: 0x0023, 0x12d0: 0x0025, 0x12d1: 0x0027, + 0x12d2: 0x0029, 0x12d3: 0x002b, 0x12d4: 0x002d, 0x12d5: 0x002f, 0x12d6: 0x0031, 0x12d7: 0x0033, + 0x12d8: 0x0021, 0x12d9: 0x0023, 0x12da: 0x0025, 0x12db: 0x0027, 0x12dc: 0x0029, 0x12dd: 0x002b, + 0x12de: 0x002d, 0x12df: 0x002f, 0x12e0: 0x0031, 0x12e1: 0x0033, 0x12e2: 0x0021, 0x12e3: 0x0023, + 0x12e4: 0x0025, 0x12e5: 0x0027, 0x12e6: 0x0029, 0x12e7: 0x002b, 0x12e8: 0x002d, 0x12e9: 0x002f, + 0x12ea: 0x0031, 0x12eb: 0x0033, 0x12ec: 0x0021, 0x12ed: 0x0023, 0x12ee: 0x0025, 0x12ef: 0x0027, + 0x12f0: 0x0029, 0x12f1: 0x002b, 0x12f2: 0x002d, 0x12f3: 0x002f, 0x12f4: 0x0031, 0x12f5: 0x0033, + 0x12f6: 0x0021, 0x12f7: 0x0023, 0x12f8: 0x0025, 0x12f9: 0x0027, 0x12fa: 0x0029, 0x12fb: 0x002b, + 0x12fc: 0x002d, 0x12fd: 0x002f, 0x12fe: 0x0031, 0x12ff: 0x0033, + // Block 0x4c, offset 0x1300 + 0x1300: 0x0230, 0x1301: 0x0233, 0x1302: 0x023f, 0x1303: 0x0248, 0x1305: 0x0281, + 0x1306: 0x0251, 0x1307: 0x0242, 0x1308: 0x0260, 0x1309: 0x0287, 0x130a: 0x0272, 0x130b: 0x0275, + 0x130c: 0x0278, 0x130d: 0x027b, 0x130e: 0x0254, 0x130f: 0x0266, 0x1310: 0x026c, 0x1311: 0x025a, + 0x1312: 0x026f, 0x1313: 0x024e, 0x1314: 0x0257, 0x1315: 0x0239, 0x1316: 0x023c, 0x1317: 0x0245, + 0x1318: 0x024b, 0x1319: 0x025d, 0x131a: 0x0263, 0x131b: 0x0269, 0x131c: 0x028a, 0x131d: 0x02db, + 0x131e: 0x02c3, 0x131f: 0x028d, 0x1321: 0x0233, 0x1322: 0x023f, + 0x1324: 0x027e, 0x1327: 0x0242, 0x1329: 0x0287, + 0x132a: 0x0272, 0x132b: 0x0275, 0x132c: 0x0278, 0x132d: 0x027b, 0x132e: 0x0254, 0x132f: 0x0266, + 0x1330: 0x026c, 0x1331: 0x025a, 0x1332: 0x026f, 0x1334: 0x0257, 0x1335: 0x0239, + 0x1336: 0x023c, 0x1337: 0x0245, 0x1339: 0x025d, 0x133b: 0x0269, + // Block 0x4d, offset 0x1340 + 0x1342: 0x023f, + 0x1347: 0x0242, 0x1349: 0x0287, 0x134b: 0x0275, + 0x134d: 0x027b, 0x134e: 0x0254, 0x134f: 0x0266, 0x1351: 0x025a, + 0x1352: 0x026f, 0x1354: 0x0257, 0x1357: 0x0245, + 0x1359: 0x025d, 0x135b: 0x0269, 0x135d: 0x02db, + 0x135f: 0x028d, 0x1361: 0x0233, 0x1362: 0x023f, + 0x1364: 0x027e, 0x1367: 0x0242, 0x1368: 0x0260, 0x1369: 0x0287, + 0x136a: 0x0272, 0x136c: 0x0278, 0x136d: 0x027b, 0x136e: 0x0254, 0x136f: 0x0266, + 0x1370: 0x026c, 0x1371: 0x025a, 0x1372: 0x026f, 0x1374: 0x0257, 0x1375: 0x0239, + 0x1376: 0x023c, 0x1377: 0x0245, 0x1379: 0x025d, 0x137a: 0x0263, 0x137b: 0x0269, + 0x137c: 0x028a, 0x137e: 0x02c3, + // Block 0x4e, offset 0x1380 + 0x1380: 0x0230, 0x1381: 0x0233, 0x1382: 0x023f, 0x1383: 0x0248, 0x1384: 0x027e, 0x1385: 0x0281, + 0x1386: 0x0251, 0x1387: 0x0242, 0x1388: 0x0260, 0x1389: 0x0287, 0x138b: 0x0275, + 0x138c: 0x0278, 0x138d: 0x027b, 0x138e: 0x0254, 0x138f: 0x0266, 0x1390: 0x026c, 0x1391: 0x025a, + 0x1392: 0x026f, 0x1393: 0x024e, 0x1394: 0x0257, 0x1395: 0x0239, 0x1396: 0x023c, 0x1397: 0x0245, + 0x1398: 0x024b, 0x1399: 0x025d, 0x139a: 0x0263, 0x139b: 0x0269, + 0x13a1: 0x0233, 0x13a2: 0x023f, 0x13a3: 0x0248, + 0x13a5: 0x0281, 0x13a6: 0x0251, 0x13a7: 0x0242, 0x13a8: 0x0260, 0x13a9: 0x0287, + 0x13ab: 0x0275, 0x13ac: 0x0278, 0x13ad: 0x027b, 0x13ae: 0x0254, 0x13af: 0x0266, + 0x13b0: 0x026c, 0x13b1: 0x025a, 0x13b2: 0x026f, 0x13b3: 0x024e, 0x13b4: 0x0257, 0x13b5: 0x0239, + 0x13b6: 0x023c, 0x13b7: 0x0245, 0x13b8: 0x024b, 0x13b9: 0x025d, 0x13ba: 0x0263, 0x13bb: 0x0269, + // Block 0x4f, offset 0x13c0 + 0x13c0: 0x19b8, 0x13c1: 0x19b5, 0x13c2: 0x19bb, 0x13c3: 0x19df, 0x13c4: 0x1a03, 0x13c5: 0x1a27, + 0x13c6: 0x1a4b, 0x13c7: 0x1a54, 0x13c8: 0x1a5a, 0x13c9: 0x1a60, 0x13ca: 0x1a66, + 0x13d0: 0x1bcb, 0x13d1: 0x1bcf, + 0x13d2: 0x1bd3, 0x13d3: 0x1bd7, 0x13d4: 0x1bdb, 0x13d5: 0x1bdf, 0x13d6: 0x1be3, 0x13d7: 0x1be7, + 0x13d8: 0x1beb, 0x13d9: 0x1bef, 0x13da: 0x1bf3, 0x13db: 0x1bf7, 0x13dc: 0x1bfb, 0x13dd: 0x1bff, + 0x13de: 0x1c03, 0x13df: 0x1c07, 0x13e0: 0x1c0b, 0x13e1: 0x1c0f, 0x13e2: 0x1c13, 0x13e3: 0x1c17, + 0x13e4: 0x1c1b, 0x13e5: 0x1c1f, 0x13e6: 0x1c23, 0x13e7: 0x1c27, 0x13e8: 0x1c2b, 0x13e9: 0x1c2f, + 0x13ea: 0x28c6, 0x13eb: 0x0047, 0x13ec: 0x0065, 0x13ed: 0x1a7b, 0x13ee: 0x1af0, + 0x13f0: 0x0043, 0x13f1: 0x0045, 0x13f2: 0x0047, 0x13f3: 0x0049, 0x13f4: 0x004b, 0x13f5: 0x004d, + 0x13f6: 0x004f, 0x13f7: 0x0051, 0x13f8: 0x0053, 0x13f9: 0x0055, 0x13fa: 0x0057, 0x13fb: 0x0059, + 0x13fc: 0x005b, 0x13fd: 0x005d, 0x13fe: 0x005f, 0x13ff: 0x0061, + // Block 0x50, offset 0x1400 + 0x1400: 0x2855, 0x1401: 0x286a, 0x1402: 0x0572, + 0x1410: 0x0c7e, 0x1411: 0x0ab6, + 0x1412: 0x0942, 0x1413: 0x45ab, 0x1414: 0x078a, 0x1415: 0x0a5e, 0x1416: 0x139e, 0x1417: 0x0a6e, + 0x1418: 0x0796, 0x1419: 0x0d46, 0x141a: 0x0f1e, 0x141b: 0x0d1e, 0x141c: 0x0896, 0x141d: 0x0bda, + 0x141e: 0x082e, 0x141f: 0x0d26, 0x1420: 0x0882, 0x1421: 0x1186, 0x1422: 0x0ff2, 0x1423: 0x13fa, + 0x1424: 0x0a42, 0x1425: 0x097a, 0x1426: 0x0ed2, 0x1427: 0x0c8a, 0x1428: 0x0cb6, 0x1429: 0x072e, + 0x142a: 0x073a, 0x142b: 0x147a, 0x142c: 0x0b4a, 0x142d: 0x0756, 0x142e: 0x095e, 0x142f: 0x0caa, + 0x1430: 0x1422, 0x1431: 0x0c82, 0x1432: 0x10de, 0x1433: 0x111a, 0x1434: 0x0966, 0x1435: 0x0eb2, + 0x1436: 0x0d7a, 0x1437: 0x0d76, 0x1438: 0x1006, 0x1439: 0x089a, 0x143a: 0x09c6, + // Block 0x51, offset 0x1440 + 0x1440: 0x076a, 0x1441: 0x0762, 0x1442: 0x0772, 0x1443: 0x16a6, 0x1444: 0x07b6, 0x1445: 0x07c6, + 0x1446: 0x07ca, 0x1447: 0x07d2, 0x1448: 0x07da, 0x1449: 0x07de, 0x144a: 0x07ea, 0x144b: 0x07e2, + 0x144c: 0x0622, 0x144d: 0x16ba, 0x144e: 0x07fe, 0x144f: 0x0802, 0x1450: 0x0806, 0x1451: 0x0822, + 0x1452: 0x16ab, 0x1453: 0x0626, 0x1454: 0x080e, 0x1455: 0x082e, 0x1456: 0x16b5, 0x1457: 0x083e, + 0x1458: 0x0846, 0x1459: 0x07a6, 0x145a: 0x084e, 0x145b: 0x0852, 0x145c: 0x1890, 0x145d: 0x086e, + 0x145e: 0x0876, 0x145f: 0x062e, 0x1460: 0x088e, 0x1461: 0x0892, 0x1462: 0x089a, 0x1463: 0x089e, + 0x1464: 0x0632, 0x1465: 0x08b6, 0x1466: 0x08ba, 0x1467: 0x08c6, 0x1468: 0x08d2, 0x1469: 0x08d6, + 0x146a: 0x08da, 0x146b: 0x08e2, 0x146c: 0x0902, 0x146d: 0x0906, 0x146e: 0x090e, 0x146f: 0x091e, + 0x1470: 0x0926, 0x1471: 0x092a, 0x1472: 0x092a, 0x1473: 0x092a, 0x1474: 0x16c9, 0x1475: 0x0f02, + 0x1476: 0x093e, 0x1477: 0x0946, 0x1478: 0x16ce, 0x1479: 0x0952, 0x147a: 0x095a, 0x147b: 0x0962, + 0x147c: 0x098a, 0x147d: 0x0976, 0x147e: 0x0982, 0x147f: 0x0986, + // Block 0x52, offset 0x1480 + 0x1480: 0x098e, 0x1481: 0x0996, 0x1482: 0x099a, 0x1483: 0x09a2, 0x1484: 0x09aa, 0x1485: 0x09ae, + 0x1486: 0x09ae, 0x1487: 0x09b6, 0x1488: 0x09be, 0x1489: 0x09c2, 0x148a: 0x09ce, 0x148b: 0x09f2, + 0x148c: 0x09d6, 0x148d: 0x09f6, 0x148e: 0x09da, 0x148f: 0x09e2, 0x1490: 0x087a, 0x1491: 0x0a3e, + 0x1492: 0x0a06, 0x1493: 0x0a0a, 0x1494: 0x0a0e, 0x1495: 0x0a02, 0x1496: 0x0a16, 0x1497: 0x0a12, + 0x1498: 0x0a2a, 0x1499: 0x16d3, 0x149a: 0x0a46, 0x149b: 0x0a4a, 0x149c: 0x0a52, 0x149d: 0x0a5e, + 0x149e: 0x0a66, 0x149f: 0x0a82, 0x14a0: 0x16d8, 0x14a1: 0x16dd, 0x14a2: 0x0a8e, 0x14a3: 0x0a92, + 0x14a4: 0x0a96, 0x14a5: 0x0a8a, 0x14a6: 0x0a9e, 0x14a7: 0x0636, 0x14a8: 0x063a, 0x14a9: 0x0aa6, + 0x14aa: 0x0aae, 0x14ab: 0x0aae, 0x14ac: 0x16e2, 0x14ad: 0x0aca, 0x14ae: 0x0ace, 0x14af: 0x0ad2, + 0x14b0: 0x0ada, 0x14b1: 0x16e7, 0x14b2: 0x0ae2, 0x14b3: 0x0ae6, 0x14b4: 0x0bbe, 0x14b5: 0x0aee, + 0x14b6: 0x063e, 0x14b7: 0x0afa, 0x14b8: 0x0b0a, 0x14b9: 0x0b16, 0x14ba: 0x0b12, 0x14bb: 0x16f1, + 0x14bc: 0x0b1e, 0x14bd: 0x16f6, 0x14be: 0x0b2a, 0x14bf: 0x0b26, + // Block 0x53, offset 0x14c0 + 0x14c0: 0x0b2e, 0x14c1: 0x0b3e, 0x14c2: 0x0b42, 0x14c3: 0x0642, 0x14c4: 0x0b52, 0x14c5: 0x0b5a, + 0x14c6: 0x0b5e, 0x14c7: 0x0b62, 0x14c8: 0x0646, 0x14c9: 0x16fb, 0x14ca: 0x064a, 0x14cb: 0x0b7e, + 0x14cc: 0x0b82, 0x14cd: 0x0b86, 0x14ce: 0x0b8e, 0x14cf: 0x18c2, 0x14d0: 0x0ba6, 0x14d1: 0x1705, + 0x14d2: 0x1705, 0x14d3: 0x1246, 0x14d4: 0x0bb6, 0x14d5: 0x0bb6, 0x14d6: 0x064e, 0x14d7: 0x1728, + 0x14d8: 0x17fa, 0x14d9: 0x0bc6, 0x14da: 0x0bce, 0x14db: 0x0652, 0x14dc: 0x0be2, 0x14dd: 0x0bf2, + 0x14de: 0x0bf6, 0x14df: 0x0bfe, 0x14e0: 0x0c0e, 0x14e1: 0x065a, 0x14e2: 0x0656, 0x14e3: 0x0c12, + 0x14e4: 0x170a, 0x14e5: 0x0c16, 0x14e6: 0x0c2a, 0x14e7: 0x0c2e, 0x14e8: 0x0c32, 0x14e9: 0x0c2e, + 0x14ea: 0x0c3e, 0x14eb: 0x0c42, 0x14ec: 0x0c52, 0x14ed: 0x0c4a, 0x14ee: 0x0c4e, 0x14ef: 0x0c56, + 0x14f0: 0x0c5a, 0x14f1: 0x0c5e, 0x14f2: 0x0c6a, 0x14f3: 0x0c6e, 0x14f4: 0x0c86, 0x14f5: 0x0c8e, + 0x14f6: 0x0c9e, 0x14f7: 0x0cb2, 0x14f8: 0x1719, 0x14f9: 0x0cae, 0x14fa: 0x0ca2, 0x14fb: 0x0cba, + 0x14fc: 0x0cc2, 0x14fd: 0x0cd6, 0x14fe: 0x171e, 0x14ff: 0x0cde, + // Block 0x54, offset 0x1500 + 0x1500: 0x0cd2, 0x1501: 0x0cca, 0x1502: 0x065e, 0x1503: 0x0ce6, 0x1504: 0x0cee, 0x1505: 0x0cf6, + 0x1506: 0x0cea, 0x1507: 0x0662, 0x1508: 0x0d06, 0x1509: 0x0d0e, 0x150a: 0x1723, 0x150b: 0x0d3a, + 0x150c: 0x0d6e, 0x150d: 0x0d4a, 0x150e: 0x066e, 0x150f: 0x0d56, 0x1510: 0x066a, 0x1511: 0x0666, + 0x1512: 0x0832, 0x1513: 0x0836, 0x1514: 0x0d72, 0x1515: 0x0d5a, 0x1516: 0x121a, 0x1517: 0x06d2, + 0x1518: 0x0d7e, 0x1519: 0x0d82, 0x151a: 0x0d86, 0x151b: 0x0d9a, 0x151c: 0x0d92, 0x151d: 0x173c, + 0x151e: 0x0672, 0x151f: 0x0dae, 0x1520: 0x0da2, 0x1521: 0x0dbe, 0x1522: 0x0dc6, 0x1523: 0x1746, + 0x1524: 0x0dca, 0x1525: 0x0db6, 0x1526: 0x0dd2, 0x1527: 0x0676, 0x1528: 0x0dd6, 0x1529: 0x0dda, + 0x152a: 0x0dde, 0x152b: 0x0dea, 0x152c: 0x174b, 0x152d: 0x0df2, 0x152e: 0x067a, 0x152f: 0x0dfe, + 0x1530: 0x1750, 0x1531: 0x0e02, 0x1532: 0x067e, 0x1533: 0x0e0e, 0x1534: 0x0e1a, 0x1535: 0x0e26, + 0x1536: 0x0e2a, 0x1537: 0x1755, 0x1538: 0x16ec, 0x1539: 0x175a, 0x153a: 0x0e4a, 0x153b: 0x175f, + 0x153c: 0x0e56, 0x153d: 0x0e5e, 0x153e: 0x0e4e, 0x153f: 0x0e6a, + // Block 0x55, offset 0x1540 + 0x1540: 0x0e7a, 0x1541: 0x0e8a, 0x1542: 0x0e7e, 0x1543: 0x0e82, 0x1544: 0x0e8e, 0x1545: 0x0e92, + 0x1546: 0x1764, 0x1547: 0x0e76, 0x1548: 0x0eaa, 0x1549: 0x0eae, 0x154a: 0x0682, 0x154b: 0x0ec2, + 0x154c: 0x0ebe, 0x154d: 0x1769, 0x154e: 0x0ea2, 0x154f: 0x0ede, 0x1550: 0x176e, 0x1551: 0x1773, + 0x1552: 0x0ee2, 0x1553: 0x0ef6, 0x1554: 0x0ef2, 0x1555: 0x0eee, 0x1556: 0x0686, 0x1557: 0x0efa, + 0x1558: 0x0f0a, 0x1559: 0x0f06, 0x155a: 0x0f12, 0x155b: 0x16b0, 0x155c: 0x0f22, 0x155d: 0x1778, + 0x155e: 0x0f2e, 0x155f: 0x1782, 0x1560: 0x0f42, 0x1561: 0x0f4e, 0x1562: 0x0f62, 0x1563: 0x1787, + 0x1564: 0x0f76, 0x1565: 0x0f7a, 0x1566: 0x178c, 0x1567: 0x1791, 0x1568: 0x0f96, 0x1569: 0x0fa6, + 0x156a: 0x068a, 0x156b: 0x0faa, 0x156c: 0x068e, 0x156d: 0x068e, 0x156e: 0x0fc2, 0x156f: 0x0fc6, + 0x1570: 0x0fce, 0x1571: 0x0fd2, 0x1572: 0x0fde, 0x1573: 0x0692, 0x1574: 0x0ff6, 0x1575: 0x1796, + 0x1576: 0x1012, 0x1577: 0x179b, 0x1578: 0x101e, 0x1579: 0x1700, 0x157a: 0x102e, 0x157b: 0x17a0, + 0x157c: 0x17a5, 0x157d: 0x17aa, 0x157e: 0x0696, 0x157f: 0x069a, + // Block 0x56, offset 0x1580 + 0x1580: 0x1066, 0x1581: 0x17b4, 0x1582: 0x17af, 0x1583: 0x17b9, 0x1584: 0x17be, 0x1585: 0x106e, + 0x1586: 0x1072, 0x1587: 0x1072, 0x1588: 0x107a, 0x1589: 0x06a2, 0x158a: 0x107e, 0x158b: 0x06a6, + 0x158c: 0x06aa, 0x158d: 0x17c8, 0x158e: 0x1092, 0x158f: 0x109a, 0x1590: 0x10a6, 0x1591: 0x06ae, + 0x1592: 0x17cd, 0x1593: 0x10ca, 0x1594: 0x17d2, 0x1595: 0x17d7, 0x1596: 0x10ea, 0x1597: 0x1102, + 0x1598: 0x06b2, 0x1599: 0x110a, 0x159a: 0x110e, 0x159b: 0x1112, 0x159c: 0x17dc, 0x159d: 0x17e1, + 0x159e: 0x17e1, 0x159f: 0x112a, 0x15a0: 0x06b6, 0x15a1: 0x17e6, 0x15a2: 0x113e, 0x15a3: 0x1142, + 0x15a4: 0x06ba, 0x15a5: 0x17eb, 0x15a6: 0x115e, 0x15a7: 0x06be, 0x15a8: 0x116e, 0x15a9: 0x1166, + 0x15aa: 0x1176, 0x15ab: 0x17f5, 0x15ac: 0x118e, 0x15ad: 0x06c2, 0x15ae: 0x119a, 0x15af: 0x11a2, + 0x15b0: 0x11b2, 0x15b1: 0x06c6, 0x15b2: 0x17ff, 0x15b3: 0x1804, 0x15b4: 0x06ca, 0x15b5: 0x1809, + 0x15b6: 0x11ca, 0x15b7: 0x180e, 0x15b8: 0x11d6, 0x15b9: 0x11e2, 0x15ba: 0x11ea, 0x15bb: 0x1813, + 0x15bc: 0x1818, 0x15bd: 0x11fe, 0x15be: 0x181d, 0x15bf: 0x1206, + // Block 0x57, offset 0x15c0 + 0x15c0: 0x172d, 0x15c1: 0x06ce, 0x15c2: 0x121e, 0x15c3: 0x1222, 0x15c4: 0x06d6, 0x15c5: 0x1226, + 0x15c6: 0x0aa2, 0x15c7: 0x1822, 0x15c8: 0x1827, 0x15c9: 0x1732, 0x15ca: 0x1737, 0x15cb: 0x1246, + 0x15cc: 0x124a, 0x15cd: 0x1462, 0x15ce: 0x06da, 0x15cf: 0x1276, 0x15d0: 0x1272, 0x15d1: 0x127a, + 0x15d2: 0x08ae, 0x15d3: 0x127e, 0x15d4: 0x1282, 0x15d5: 0x1286, 0x15d6: 0x128e, 0x15d7: 0x182c, + 0x15d8: 0x128a, 0x15d9: 0x1292, 0x15da: 0x12a6, 0x15db: 0x12aa, 0x15dc: 0x1296, 0x15dd: 0x12ae, + 0x15de: 0x12c2, 0x15df: 0x12d6, 0x15e0: 0x12a2, 0x15e1: 0x12b6, 0x15e2: 0x12ba, 0x15e3: 0x12be, + 0x15e4: 0x1831, 0x15e5: 0x183b, 0x15e6: 0x1836, 0x15e7: 0x06de, 0x15e8: 0x12de, 0x15e9: 0x12e2, + 0x15ea: 0x12ea, 0x15eb: 0x184f, 0x15ec: 0x12ee, 0x15ed: 0x1840, 0x15ee: 0x06e2, 0x15ef: 0x06e6, + 0x15f0: 0x1845, 0x15f1: 0x184a, 0x15f2: 0x06ea, 0x15f3: 0x130e, 0x15f4: 0x1312, 0x15f5: 0x1316, + 0x15f6: 0x131a, 0x15f7: 0x1326, 0x15f8: 0x1322, 0x15f9: 0x132e, 0x15fa: 0x132a, 0x15fb: 0x133a, + 0x15fc: 0x1332, 0x15fd: 0x1336, 0x15fe: 0x133e, 0x15ff: 0x06ee, + // Block 0x58, offset 0x1600 + 0x1600: 0x1346, 0x1601: 0x134a, 0x1602: 0x06f2, 0x1603: 0x135a, 0x1604: 0x135e, 0x1605: 0x1854, + 0x1606: 0x136a, 0x1607: 0x136e, 0x1608: 0x06f6, 0x1609: 0x137a, 0x160a: 0x062a, 0x160b: 0x1859, + 0x160c: 0x185e, 0x160d: 0x06fa, 0x160e: 0x06fe, 0x160f: 0x13a6, 0x1610: 0x13be, 0x1611: 0x13da, + 0x1612: 0x13ea, 0x1613: 0x1863, 0x1614: 0x13fe, 0x1615: 0x1402, 0x1616: 0x141a, 0x1617: 0x1426, + 0x1618: 0x186d, 0x1619: 0x16bf, 0x161a: 0x1432, 0x161b: 0x142e, 0x161c: 0x143a, 0x161d: 0x16c4, + 0x161e: 0x1446, 0x161f: 0x1452, 0x1620: 0x1872, 0x1621: 0x1877, 0x1622: 0x1492, 0x1623: 0x149e, + 0x1624: 0x14a6, 0x1625: 0x187c, 0x1626: 0x14aa, 0x1627: 0x14d2, 0x1628: 0x14de, 0x1629: 0x14e2, + 0x162a: 0x14da, 0x162b: 0x14ee, 0x162c: 0x14f2, 0x162d: 0x1881, 0x162e: 0x14fe, 0x162f: 0x0702, + 0x1630: 0x1506, 0x1631: 0x1886, 0x1632: 0x0706, 0x1633: 0x153e, 0x1634: 0x0b32, 0x1635: 0x1556, + 0x1636: 0x188b, 0x1637: 0x1895, 0x1638: 0x070a, 0x1639: 0x070e, 0x163a: 0x157e, 0x163b: 0x189a, + 0x163c: 0x0712, 0x163d: 0x189f, 0x163e: 0x1596, 0x163f: 0x1596, + // Block 0x59, offset 0x1640 + 0x1640: 0x159e, 0x1641: 0x18a4, 0x1642: 0x15b6, 0x1643: 0x0716, 0x1644: 0x15c6, 0x1645: 0x15d2, + 0x1646: 0x15da, 0x1647: 0x15e2, 0x1648: 0x071a, 0x1649: 0x18a9, 0x164a: 0x15f6, 0x164b: 0x1612, + 0x164c: 0x161e, 0x164d: 0x071e, 0x164e: 0x0722, 0x164f: 0x1622, 0x1650: 0x18ae, 0x1651: 0x0726, + 0x1652: 0x18b3, 0x1653: 0x18b8, 0x1654: 0x18bd, 0x1655: 0x1646, 0x1656: 0x072a, 0x1657: 0x165a, + 0x1658: 0x1662, 0x1659: 0x1666, 0x165a: 0x166e, 0x165b: 0x1676, 0x165c: 0x167e, 0x165d: 0x18c7, +} + +// nfkcSparseOffset: 134 entries, 268 bytes +var nfkcSparseOffset = []uint16{0x0, 0xe, 0x12, 0x1b, 0x25, 0x35, 0x37, 0x3c, 0x47, 0x56, 0x63, 0x6b, 0x6f, 0x74, 0x76, 0x85, 0x8d, 0x94, 0x97, 0x9f, 0xa3, 0xa7, 0xa9, 0xab, 0xb4, 0xb8, 0xbf, 0xc4, 0xc7, 0xd1, 0xd3, 0xda, 0xe2, 0xe6, 0xe8, 0xeb, 0xef, 0xf5, 0x106, 0x112, 0x114, 0x11a, 0x11c, 0x11e, 0x120, 0x122, 0x124, 0x126, 0x128, 0x12b, 0x12e, 0x130, 0x133, 0x136, 0x13a, 0x143, 0x145, 0x148, 0x14a, 0x154, 0x15f, 0x16e, 0x17c, 0x18a, 0x19a, 0x1a8, 0x1af, 0x1b5, 0x1c4, 0x1c8, 0x1ca, 0x1ce, 0x1d0, 0x1d3, 0x1d5, 0x1d8, 0x1da, 0x1dd, 0x1df, 0x1e1, 0x1e3, 0x1ef, 0x1f9, 0x200, 0x20d, 0x210, 0x212, 0x214, 0x216, 0x218, 0x21a, 0x21d, 0x21f, 0x221, 0x223, 0x225, 0x22b, 0x22e, 0x230, 0x237, 0x23d, 0x243, 0x24b, 0x251, 0x257, 0x25d, 0x261, 0x263, 0x272, 0x274, 0x27a, 0x282, 0x289, 0x28c, 0x299, 0x2a3, 0x2a5, 0x2a7, 0x2ab, 0x2b0, 0x2bc, 0x2c1, 0x2ca, 0x2d0, 0x2d5, 0x2d9, 0x2de, 0x2e2, 0x2f2, 0x300, 0x30e, 0x31c, 0x326, 0x328} + +// nfkcSparseValues: 818 entries, 3272 bytes +var nfkcSparseValues = [818]valueRange{ + // Block 0x0, offset 0x1 + {value: 0x0002, lo: 0x0d}, + {value: 0x0001, lo: 0xa0, hi: 0xa0}, + {value: 0x425f, lo: 0xa8, hi: 0xa8}, + {value: 0x0083, lo: 0xaa, hi: 0xaa}, + {value: 0x424b, lo: 0xaf, hi: 0xaf}, + {value: 0x0025, lo: 0xb2, hi: 0xb3}, + {value: 0x4241, lo: 0xb4, hi: 0xb4}, + {value: 0x01d9, lo: 0xb5, hi: 0xb5}, + {value: 0x4278, lo: 0xb8, hi: 0xb8}, + {value: 0x0023, lo: 0xb9, hi: 0xb9}, + {value: 0x009f, lo: 0xba, hi: 0xba}, + {value: 0x235b, lo: 0xbc, hi: 0xbc}, + {value: 0x234f, lo: 0xbd, hi: 0xbd}, + {value: 0x23f1, lo: 0xbe, hi: 0xbe}, + // Block 0x1, offset 0x2 + {value: 0x0091, lo: 0x03}, + {value: 0x46c9, lo: 0xa0, hi: 0xa1}, + {value: 0x46fb, lo: 0xaf, hi: 0xb0}, + {value: 0xa000, lo: 0xb7, hi: 0xb7}, + // Block 0x2, offset 0x3 + {value: 0x0003, lo: 0x08}, + {value: 0xa000, lo: 0x92, hi: 0x92}, + {value: 0x0091, lo: 0xb0, hi: 0xb0}, + {value: 0x0119, lo: 0xb1, hi: 0xb1}, + {value: 0x0095, lo: 0xb2, hi: 0xb2}, + {value: 0x00a5, lo: 0xb3, hi: 0xb3}, + {value: 0x0140, lo: 0xb4, hi: 0xb6}, + {value: 0x00af, lo: 0xb7, hi: 0xb7}, + {value: 0x00b3, lo: 0xb8, hi: 0xb8}, + // Block 0x3, offset 0x4 + {value: 0x000a, lo: 0x09}, + {value: 0x4255, lo: 0x98, hi: 0x98}, + {value: 0x425a, lo: 0x99, hi: 0x9a}, + {value: 0x427d, lo: 0x9b, hi: 0x9b}, + {value: 0x4246, lo: 0x9c, hi: 0x9c}, + {value: 0x4269, lo: 0x9d, hi: 0x9d}, + {value: 0x0113, lo: 0xa0, hi: 0xa0}, + {value: 0x0099, lo: 0xa1, hi: 0xa1}, + {value: 0x00a7, lo: 0xa2, hi: 0xa3}, + {value: 0x0164, lo: 0xa4, hi: 0xa4}, + // Block 0x4, offset 0x5 + {value: 0x0000, lo: 0x0f}, + {value: 0xa000, lo: 0x83, hi: 0x83}, + {value: 0xa000, lo: 0x87, hi: 0x87}, + {value: 0xa000, lo: 0x8b, hi: 0x8b}, + {value: 0xa000, lo: 0x8d, hi: 0x8d}, + {value: 0x378c, lo: 0x90, hi: 0x90}, + {value: 0x3798, lo: 0x91, hi: 0x91}, + {value: 0x3786, lo: 0x93, hi: 0x93}, + {value: 0xa000, lo: 0x96, hi: 0x96}, + {value: 0x37fe, lo: 0x97, hi: 0x97}, + {value: 0x37c8, lo: 0x9c, hi: 0x9c}, + {value: 0x37b0, lo: 0x9d, hi: 0x9d}, + {value: 0x37da, lo: 0x9e, hi: 0x9e}, + {value: 0xa000, lo: 0xb4, hi: 0xb5}, + {value: 0x3804, lo: 0xb6, hi: 0xb6}, + {value: 0x380a, lo: 0xb7, hi: 0xb7}, + // Block 0x5, offset 0x6 + {value: 0x0000, lo: 0x01}, + {value: 0x8132, lo: 0x83, hi: 0x87}, + // Block 0x6, offset 0x7 + {value: 0x0001, lo: 0x04}, + {value: 0x8113, lo: 0x81, hi: 0x82}, + {value: 0x8132, lo: 0x84, hi: 0x84}, + {value: 0x812d, lo: 0x85, hi: 0x85}, + {value: 0x810d, lo: 0x87, hi: 0x87}, + // Block 0x7, offset 0x8 + {value: 0x0000, lo: 0x0a}, + {value: 0x8132, lo: 0x90, hi: 0x97}, + {value: 0x8119, lo: 0x98, hi: 0x98}, + {value: 0x811a, lo: 0x99, hi: 0x99}, + {value: 0x811b, lo: 0x9a, hi: 0x9a}, + {value: 0x3828, lo: 0xa2, hi: 0xa2}, + {value: 0x382e, lo: 0xa3, hi: 0xa3}, + {value: 0x383a, lo: 0xa4, hi: 0xa4}, + {value: 0x3834, lo: 0xa5, hi: 0xa5}, + {value: 0x3840, lo: 0xa6, hi: 0xa6}, + {value: 0xa000, lo: 0xa7, hi: 0xa7}, + // Block 0x8, offset 0x9 + {value: 0x0000, lo: 0x0e}, + {value: 0x3852, lo: 0x80, hi: 0x80}, + {value: 0xa000, lo: 0x81, hi: 0x81}, + {value: 0x3846, lo: 0x82, hi: 0x82}, + {value: 0xa000, lo: 0x92, hi: 0x92}, + {value: 0x384c, lo: 0x93, hi: 0x93}, + {value: 0xa000, lo: 0x95, hi: 0x95}, + {value: 0x8132, lo: 0x96, hi: 0x9c}, + {value: 0x8132, lo: 0x9f, hi: 0xa2}, + {value: 0x812d, lo: 0xa3, hi: 0xa3}, + {value: 0x8132, lo: 0xa4, hi: 0xa4}, + {value: 0x8132, lo: 0xa7, hi: 0xa8}, + {value: 0x812d, lo: 0xaa, hi: 0xaa}, + {value: 0x8132, lo: 0xab, hi: 0xac}, + {value: 0x812d, lo: 0xad, hi: 0xad}, + // Block 0x9, offset 0xa + {value: 0x0000, lo: 0x0c}, + {value: 0x811f, lo: 0x91, hi: 0x91}, + {value: 0x8132, lo: 0xb0, hi: 0xb0}, + {value: 0x812d, lo: 0xb1, hi: 0xb1}, + {value: 0x8132, lo: 0xb2, hi: 0xb3}, + {value: 0x812d, lo: 0xb4, hi: 0xb4}, + {value: 0x8132, lo: 0xb5, hi: 0xb6}, + {value: 0x812d, lo: 0xb7, hi: 0xb9}, + {value: 0x8132, lo: 0xba, hi: 0xba}, + {value: 0x812d, lo: 0xbb, hi: 0xbc}, + {value: 0x8132, lo: 0xbd, hi: 0xbd}, + {value: 0x812d, lo: 0xbe, hi: 0xbe}, + {value: 0x8132, lo: 0xbf, hi: 0xbf}, + // Block 0xa, offset 0xb + {value: 0x0005, lo: 0x07}, + {value: 0x8132, lo: 0x80, hi: 0x80}, + {value: 0x8132, lo: 0x81, hi: 0x81}, + {value: 0x812d, lo: 0x82, hi: 0x83}, + {value: 0x812d, lo: 0x84, hi: 0x85}, + {value: 0x812d, lo: 0x86, hi: 0x87}, + {value: 0x812d, lo: 0x88, hi: 0x89}, + {value: 0x8132, lo: 0x8a, hi: 0x8a}, + // Block 0xb, offset 0xc + {value: 0x0000, lo: 0x03}, + {value: 0x8132, lo: 0xab, hi: 0xb1}, + {value: 0x812d, lo: 0xb2, hi: 0xb2}, + {value: 0x8132, lo: 0xb3, hi: 0xb3}, + // Block 0xc, offset 0xd + {value: 0x0000, lo: 0x04}, + {value: 0x8132, lo: 0x96, hi: 0x99}, + {value: 0x8132, lo: 0x9b, hi: 0xa3}, + {value: 0x8132, lo: 0xa5, hi: 0xa7}, + {value: 0x8132, lo: 0xa9, hi: 0xad}, + // Block 0xd, offset 0xe + {value: 0x0000, lo: 0x01}, + {value: 0x812d, lo: 0x99, hi: 0x9b}, + // Block 0xe, offset 0xf + {value: 0x0000, lo: 0x0e}, + {value: 0x8132, lo: 0xa4, hi: 0xa5}, + {value: 0x812d, lo: 0xa6, hi: 0xa6}, + {value: 0x8132, lo: 0xa7, hi: 0xa8}, + {value: 0x812d, lo: 0xa9, hi: 0xa9}, + {value: 0x8132, lo: 0xaa, hi: 0xac}, + {value: 0x812d, lo: 0xad, hi: 0xaf}, + {value: 0x8116, lo: 0xb0, hi: 0xb0}, + {value: 0x8117, lo: 0xb1, hi: 0xb1}, + {value: 0x8118, lo: 0xb2, hi: 0xb2}, + {value: 0x8132, lo: 0xb3, hi: 0xb5}, + {value: 0x812d, lo: 0xb6, hi: 0xb6}, + {value: 0x8132, lo: 0xb7, hi: 0xb8}, + {value: 0x812d, lo: 0xb9, hi: 0xba}, + {value: 0x8132, lo: 0xbb, hi: 0xbe}, + // Block 0xf, offset 0x10 + {value: 0x0000, lo: 0x07}, + {value: 0xa000, lo: 0xa8, hi: 0xa8}, + {value: 0x3ebf, lo: 0xa9, hi: 0xa9}, + {value: 0xa000, lo: 0xb0, hi: 0xb0}, + {value: 0x3ec7, lo: 0xb1, hi: 0xb1}, + {value: 0xa000, lo: 0xb3, hi: 0xb3}, + {value: 0x3ecf, lo: 0xb4, hi: 0xb4}, + {value: 0x9902, lo: 0xbc, hi: 0xbc}, + // Block 0x10, offset 0x11 + {value: 0x0008, lo: 0x06}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + {value: 0x8132, lo: 0x91, hi: 0x91}, + {value: 0x812d, lo: 0x92, hi: 0x92}, + {value: 0x8132, lo: 0x93, hi: 0x93}, + {value: 0x8132, lo: 0x94, hi: 0x94}, + {value: 0x4503, lo: 0x98, hi: 0x9f}, + // Block 0x11, offset 0x12 + {value: 0x0000, lo: 0x02}, + {value: 0x8102, lo: 0xbc, hi: 0xbc}, + {value: 0x9900, lo: 0xbe, hi: 0xbe}, + // Block 0x12, offset 0x13 + {value: 0x0007, lo: 0x07}, + {value: 0xa000, lo: 0x87, hi: 0x87}, + {value: 0x18cc, lo: 0x8b, hi: 0x8c}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + {value: 0x9900, lo: 0x97, hi: 0x97}, + {value: 0x4543, lo: 0x9c, hi: 0x9c}, + {value: 0x454b, lo: 0x9d, hi: 0x9d}, + {value: 0x4553, lo: 0x9f, hi: 0x9f}, + // Block 0x13, offset 0x14 + {value: 0x0000, lo: 0x03}, + {value: 0x457b, lo: 0xb3, hi: 0xb3}, + {value: 0x4583, lo: 0xb6, hi: 0xb6}, + {value: 0x8102, lo: 0xbc, hi: 0xbc}, + // Block 0x14, offset 0x15 + {value: 0x0008, lo: 0x03}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + {value: 0x455b, lo: 0x99, hi: 0x9b}, + {value: 0x4573, lo: 0x9e, hi: 0x9e}, + // Block 0x15, offset 0x16 + {value: 0x0000, lo: 0x01}, + {value: 0x8102, lo: 0xbc, hi: 0xbc}, + // Block 0x16, offset 0x17 + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + // Block 0x17, offset 0x18 + {value: 0x0000, lo: 0x08}, + {value: 0xa000, lo: 0x87, hi: 0x87}, + {value: 0x18e1, lo: 0x88, hi: 0x88}, + {value: 0x18da, lo: 0x8b, hi: 0x8b}, + {value: 0x18e8, lo: 0x8c, hi: 0x8c}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + {value: 0x9900, lo: 0x96, hi: 0x97}, + {value: 0x458b, lo: 0x9c, hi: 0x9c}, + {value: 0x4593, lo: 0x9d, hi: 0x9d}, + // Block 0x18, offset 0x19 + {value: 0x0000, lo: 0x03}, + {value: 0xa000, lo: 0x92, hi: 0x92}, + {value: 0x18ef, lo: 0x94, hi: 0x94}, + {value: 0x9900, lo: 0xbe, hi: 0xbe}, + // Block 0x19, offset 0x1a + {value: 0x0000, lo: 0x06}, + {value: 0xa000, lo: 0x86, hi: 0x87}, + {value: 0x18f6, lo: 0x8a, hi: 0x8a}, + {value: 0x1904, lo: 0x8b, hi: 0x8b}, + {value: 0x18fd, lo: 0x8c, hi: 0x8c}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + {value: 0x9900, lo: 0x97, hi: 0x97}, + // Block 0x1a, offset 0x1b + {value: 0x1801, lo: 0x04}, + {value: 0xa000, lo: 0x86, hi: 0x86}, + {value: 0x3ed7, lo: 0x88, hi: 0x88}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + {value: 0x8120, lo: 0x95, hi: 0x96}, + // Block 0x1b, offset 0x1c + {value: 0x0000, lo: 0x02}, + {value: 0x8102, lo: 0xbc, hi: 0xbc}, + {value: 0xa000, lo: 0xbf, hi: 0xbf}, + // Block 0x1c, offset 0x1d + {value: 0x0000, lo: 0x09}, + {value: 0x190b, lo: 0x80, hi: 0x80}, + {value: 0x9900, lo: 0x82, hi: 0x82}, + {value: 0xa000, lo: 0x86, hi: 0x86}, + {value: 0x1912, lo: 0x87, hi: 0x87}, + {value: 0x1919, lo: 0x88, hi: 0x88}, + {value: 0x2e63, lo: 0x8a, hi: 0x8a}, + {value: 0x19a2, lo: 0x8b, hi: 0x8b}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + {value: 0x9900, lo: 0x95, hi: 0x96}, + // Block 0x1d, offset 0x1e + {value: 0x0000, lo: 0x01}, + {value: 0x9900, lo: 0xbe, hi: 0xbe}, + // Block 0x1e, offset 0x1f + {value: 0x0000, lo: 0x06}, + {value: 0xa000, lo: 0x86, hi: 0x87}, + {value: 0x1920, lo: 0x8a, hi: 0x8a}, + {value: 0x192e, lo: 0x8b, hi: 0x8b}, + {value: 0x1927, lo: 0x8c, hi: 0x8c}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + {value: 0x9900, lo: 0x97, hi: 0x97}, + // Block 0x1f, offset 0x20 + {value: 0x0007, lo: 0x07}, + {value: 0x9904, lo: 0x8a, hi: 0x8a}, + {value: 0x9900, lo: 0x8f, hi: 0x8f}, + {value: 0xa000, lo: 0x99, hi: 0x99}, + {value: 0x3edf, lo: 0x9a, hi: 0x9a}, + {value: 0x2e6a, lo: 0x9c, hi: 0x9d}, + {value: 0x1935, lo: 0x9e, hi: 0x9e}, + {value: 0x9900, lo: 0x9f, hi: 0x9f}, + // Block 0x20, offset 0x21 + {value: 0x0000, lo: 0x03}, + {value: 0x2760, lo: 0xb3, hi: 0xb3}, + {value: 0x8122, lo: 0xb8, hi: 0xb9}, + {value: 0x8104, lo: 0xba, hi: 0xba}, + // Block 0x21, offset 0x22 + {value: 0x0000, lo: 0x01}, + {value: 0x8123, lo: 0x88, hi: 0x8b}, + // Block 0x22, offset 0x23 + {value: 0x0000, lo: 0x02}, + {value: 0x2775, lo: 0xb3, hi: 0xb3}, + {value: 0x8124, lo: 0xb8, hi: 0xb9}, + // Block 0x23, offset 0x24 + {value: 0x0000, lo: 0x03}, + {value: 0x8125, lo: 0x88, hi: 0x8b}, + {value: 0x2767, lo: 0x9c, hi: 0x9c}, + {value: 0x276e, lo: 0x9d, hi: 0x9d}, + // Block 0x24, offset 0x25 + {value: 0x0000, lo: 0x05}, + {value: 0x0302, lo: 0x8c, hi: 0x8c}, + {value: 0x812d, lo: 0x98, hi: 0x99}, + {value: 0x812d, lo: 0xb5, hi: 0xb5}, + {value: 0x812d, lo: 0xb7, hi: 0xb7}, + {value: 0x812b, lo: 0xb9, hi: 0xb9}, + // Block 0x25, offset 0x26 + {value: 0x0000, lo: 0x10}, + {value: 0x2783, lo: 0x83, hi: 0x83}, + {value: 0x278a, lo: 0x8d, hi: 0x8d}, + {value: 0x2791, lo: 0x92, hi: 0x92}, + {value: 0x2798, lo: 0x97, hi: 0x97}, + {value: 0x279f, lo: 0x9c, hi: 0x9c}, + {value: 0x277c, lo: 0xa9, hi: 0xa9}, + {value: 0x8126, lo: 0xb1, hi: 0xb1}, + {value: 0x8127, lo: 0xb2, hi: 0xb2}, + {value: 0x49b7, lo: 0xb3, hi: 0xb3}, + {value: 0x8128, lo: 0xb4, hi: 0xb4}, + {value: 0x49c0, lo: 0xb5, hi: 0xb5}, + {value: 0x459b, lo: 0xb6, hi: 0xb6}, + {value: 0x45db, lo: 0xb7, hi: 0xb7}, + {value: 0x45a3, lo: 0xb8, hi: 0xb8}, + {value: 0x45e6, lo: 0xb9, hi: 0xb9}, + {value: 0x8127, lo: 0xba, hi: 0xbd}, + // Block 0x26, offset 0x27 + {value: 0x0000, lo: 0x0b}, + {value: 0x8127, lo: 0x80, hi: 0x80}, + {value: 0x49c9, lo: 0x81, hi: 0x81}, + {value: 0x8132, lo: 0x82, hi: 0x83}, + {value: 0x8104, lo: 0x84, hi: 0x84}, + {value: 0x8132, lo: 0x86, hi: 0x87}, + {value: 0x27ad, lo: 0x93, hi: 0x93}, + {value: 0x27b4, lo: 0x9d, hi: 0x9d}, + {value: 0x27bb, lo: 0xa2, hi: 0xa2}, + {value: 0x27c2, lo: 0xa7, hi: 0xa7}, + {value: 0x27c9, lo: 0xac, hi: 0xac}, + {value: 0x27a6, lo: 0xb9, hi: 0xb9}, + // Block 0x27, offset 0x28 + {value: 0x0000, lo: 0x01}, + {value: 0x812d, lo: 0x86, hi: 0x86}, + // Block 0x28, offset 0x29 + {value: 0x0000, lo: 0x05}, + {value: 0xa000, lo: 0xa5, hi: 0xa5}, + {value: 0x193c, lo: 0xa6, hi: 0xa6}, + {value: 0x9900, lo: 0xae, hi: 0xae}, + {value: 0x8102, lo: 0xb7, hi: 0xb7}, + {value: 0x8104, lo: 0xb9, hi: 0xba}, + // Block 0x29, offset 0x2a + {value: 0x0000, lo: 0x01}, + {value: 0x812d, lo: 0x8d, hi: 0x8d}, + // Block 0x2a, offset 0x2b + {value: 0x0000, lo: 0x01}, + {value: 0x0306, lo: 0xbc, hi: 0xbc}, + // Block 0x2b, offset 0x2c + {value: 0x0000, lo: 0x01}, + {value: 0xa000, lo: 0x80, hi: 0x92}, + // Block 0x2c, offset 0x2d + {value: 0x0000, lo: 0x01}, + {value: 0xb900, lo: 0xa1, hi: 0xb5}, + // Block 0x2d, offset 0x2e + {value: 0x0000, lo: 0x01}, + {value: 0x9900, lo: 0xa8, hi: 0xbf}, + // Block 0x2e, offset 0x2f + {value: 0x0000, lo: 0x01}, + {value: 0x9900, lo: 0x80, hi: 0x82}, + // Block 0x2f, offset 0x30 + {value: 0x0000, lo: 0x01}, + {value: 0x8132, lo: 0x9d, hi: 0x9f}, + // Block 0x30, offset 0x31 + {value: 0x0000, lo: 0x02}, + {value: 0x8104, lo: 0x94, hi: 0x94}, + {value: 0x8104, lo: 0xb4, hi: 0xb4}, + // Block 0x31, offset 0x32 + {value: 0x0000, lo: 0x02}, + {value: 0x8104, lo: 0x92, hi: 0x92}, + {value: 0x8132, lo: 0x9d, hi: 0x9d}, + // Block 0x32, offset 0x33 + {value: 0x0000, lo: 0x01}, + {value: 0x8131, lo: 0xa9, hi: 0xa9}, + // Block 0x33, offset 0x34 + {value: 0x0004, lo: 0x02}, + {value: 0x812e, lo: 0xb9, hi: 0xba}, + {value: 0x812d, lo: 0xbb, hi: 0xbb}, + // Block 0x34, offset 0x35 + {value: 0x0000, lo: 0x02}, + {value: 0x8132, lo: 0x97, hi: 0x97}, + {value: 0x812d, lo: 0x98, hi: 0x98}, + // Block 0x35, offset 0x36 + {value: 0x0000, lo: 0x03}, + {value: 0x8104, lo: 0xa0, hi: 0xa0}, + {value: 0x8132, lo: 0xb5, hi: 0xbc}, + {value: 0x812d, lo: 0xbf, hi: 0xbf}, + // Block 0x36, offset 0x37 + {value: 0x0000, lo: 0x08}, + {value: 0x197b, lo: 0x80, hi: 0x80}, + {value: 0x1982, lo: 0x81, hi: 0x81}, + {value: 0xa000, lo: 0x82, hi: 0x82}, + {value: 0x1989, lo: 0x83, hi: 0x83}, + {value: 0x8104, lo: 0x84, hi: 0x84}, + {value: 0x8132, lo: 0xab, hi: 0xab}, + {value: 0x812d, lo: 0xac, hi: 0xac}, + {value: 0x8132, lo: 0xad, hi: 0xb3}, + // Block 0x37, offset 0x38 + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0xaa, hi: 0xab}, + // Block 0x38, offset 0x39 + {value: 0x0000, lo: 0x02}, + {value: 0x8102, lo: 0xa6, hi: 0xa6}, + {value: 0x8104, lo: 0xb2, hi: 0xb3}, + // Block 0x39, offset 0x3a + {value: 0x0000, lo: 0x01}, + {value: 0x8102, lo: 0xb7, hi: 0xb7}, + // Block 0x3a, offset 0x3b + {value: 0x0000, lo: 0x09}, + {value: 0x8132, lo: 0x90, hi: 0x92}, + {value: 0x8101, lo: 0x94, hi: 0x94}, + {value: 0x812d, lo: 0x95, hi: 0x99}, + {value: 0x8132, lo: 0x9a, hi: 0x9b}, + {value: 0x812d, lo: 0x9c, hi: 0x9f}, + {value: 0x8132, lo: 0xa0, hi: 0xa0}, + {value: 0x8101, lo: 0xa2, hi: 0xa8}, + {value: 0x812d, lo: 0xad, hi: 0xad}, + {value: 0x8132, lo: 0xb4, hi: 0xb4}, + // Block 0x3b, offset 0x3c + {value: 0x0002, lo: 0x0a}, + {value: 0x0043, lo: 0xac, hi: 0xac}, + {value: 0x00d1, lo: 0xad, hi: 0xad}, + {value: 0x0045, lo: 0xae, hi: 0xae}, + {value: 0x0049, lo: 0xb0, hi: 0xb1}, + {value: 0x00e6, lo: 0xb2, hi: 0xb2}, + {value: 0x004f, lo: 0xb3, hi: 0xba}, + {value: 0x005f, lo: 0xbc, hi: 0xbc}, + {value: 0x00ef, lo: 0xbd, hi: 0xbd}, + {value: 0x0061, lo: 0xbe, hi: 0xbe}, + {value: 0x0065, lo: 0xbf, hi: 0xbf}, + // Block 0x3c, offset 0x3d + {value: 0x0000, lo: 0x0e}, + {value: 0x8132, lo: 0x80, hi: 0x81}, + {value: 0x812d, lo: 0x82, hi: 0x82}, + {value: 0x8132, lo: 0x83, hi: 0x89}, + {value: 0x812d, lo: 0x8a, hi: 0x8a}, + {value: 0x8132, lo: 0x8b, hi: 0x8c}, + {value: 0x8135, lo: 0x8d, hi: 0x8d}, + {value: 0x812a, lo: 0x8e, hi: 0x8e}, + {value: 0x812d, lo: 0x8f, hi: 0x8f}, + {value: 0x8129, lo: 0x90, hi: 0x90}, + {value: 0x8132, lo: 0x91, hi: 0xa6}, + {value: 0x8134, lo: 0xbc, hi: 0xbc}, + {value: 0x812d, lo: 0xbd, hi: 0xbd}, + {value: 0x8132, lo: 0xbe, hi: 0xbe}, + {value: 0x812d, lo: 0xbf, hi: 0xbf}, + // Block 0x3d, offset 0x3e + {value: 0x0000, lo: 0x0d}, + {value: 0x0001, lo: 0x80, hi: 0x8a}, + {value: 0x04aa, lo: 0x91, hi: 0x91}, + {value: 0x4282, lo: 0x97, hi: 0x97}, + {value: 0x001d, lo: 0xa4, hi: 0xa4}, + {value: 0x19b2, lo: 0xa5, hi: 0xa5}, + {value: 0x1c9b, lo: 0xa6, hi: 0xa6}, + {value: 0x0001, lo: 0xaf, hi: 0xaf}, + {value: 0x2839, lo: 0xb3, hi: 0xb3}, + {value: 0x29a6, lo: 0xb4, hi: 0xb4}, + {value: 0x2840, lo: 0xb6, hi: 0xb6}, + {value: 0x29b0, lo: 0xb7, hi: 0xb7}, + {value: 0x19ac, lo: 0xbc, hi: 0xbc}, + {value: 0x4250, lo: 0xbe, hi: 0xbe}, + // Block 0x3e, offset 0x3f + {value: 0x0002, lo: 0x0d}, + {value: 0x1a72, lo: 0x87, hi: 0x87}, + {value: 0x1a6f, lo: 0x88, hi: 0x88}, + {value: 0x19af, lo: 0x89, hi: 0x89}, + {value: 0x2b43, lo: 0x97, hi: 0x97}, + {value: 0x0001, lo: 0x9f, hi: 0x9f}, + {value: 0x0021, lo: 0xb0, hi: 0xb0}, + {value: 0x0093, lo: 0xb1, hi: 0xb1}, + {value: 0x0029, lo: 0xb4, hi: 0xb9}, + {value: 0x0017, lo: 0xba, hi: 0xba}, + {value: 0x04d6, lo: 0xbb, hi: 0xbb}, + {value: 0x003b, lo: 0xbc, hi: 0xbc}, + {value: 0x0011, lo: 0xbd, hi: 0xbe}, + {value: 0x009d, lo: 0xbf, hi: 0xbf}, + // Block 0x3f, offset 0x40 + {value: 0x0002, lo: 0x0f}, + {value: 0x0021, lo: 0x80, hi: 0x89}, + {value: 0x0017, lo: 0x8a, hi: 0x8a}, + {value: 0x04d6, lo: 0x8b, hi: 0x8b}, + {value: 0x003b, lo: 0x8c, hi: 0x8c}, + {value: 0x0011, lo: 0x8d, hi: 0x8e}, + {value: 0x0083, lo: 0x90, hi: 0x90}, + {value: 0x008b, lo: 0x91, hi: 0x91}, + {value: 0x009f, lo: 0x92, hi: 0x92}, + {value: 0x00b1, lo: 0x93, hi: 0x93}, + {value: 0x0104, lo: 0x94, hi: 0x94}, + {value: 0x0091, lo: 0x95, hi: 0x95}, + {value: 0x0097, lo: 0x96, hi: 0x99}, + {value: 0x00a1, lo: 0x9a, hi: 0x9a}, + {value: 0x00a7, lo: 0x9b, hi: 0x9c}, + {value: 0x1ad8, lo: 0xa8, hi: 0xa8}, + // Block 0x40, offset 0x41 + {value: 0x0000, lo: 0x0d}, + {value: 0x8132, lo: 0x90, hi: 0x91}, + {value: 0x8101, lo: 0x92, hi: 0x93}, + {value: 0x8132, lo: 0x94, hi: 0x97}, + {value: 0x8101, lo: 0x98, hi: 0x9a}, + {value: 0x8132, lo: 0x9b, hi: 0x9c}, + {value: 0x8132, lo: 0xa1, hi: 0xa1}, + {value: 0x8101, lo: 0xa5, hi: 0xa6}, + {value: 0x8132, lo: 0xa7, hi: 0xa7}, + {value: 0x812d, lo: 0xa8, hi: 0xa8}, + {value: 0x8132, lo: 0xa9, hi: 0xa9}, + {value: 0x8101, lo: 0xaa, hi: 0xab}, + {value: 0x812d, lo: 0xac, hi: 0xaf}, + {value: 0x8132, lo: 0xb0, hi: 0xb0}, + // Block 0x41, offset 0x42 + {value: 0x0007, lo: 0x06}, + {value: 0x22bf, lo: 0x89, hi: 0x89}, + {value: 0xa000, lo: 0x90, hi: 0x90}, + {value: 0xa000, lo: 0x92, hi: 0x92}, + {value: 0xa000, lo: 0x94, hi: 0x94}, + {value: 0x3ba0, lo: 0x9a, hi: 0x9b}, + {value: 0x3bae, lo: 0xae, hi: 0xae}, + // Block 0x42, offset 0x43 + {value: 0x000e, lo: 0x05}, + {value: 0x3bb5, lo: 0x8d, hi: 0x8e}, + {value: 0x3bbc, lo: 0x8f, hi: 0x8f}, + {value: 0xa000, lo: 0x90, hi: 0x90}, + {value: 0xa000, lo: 0x92, hi: 0x92}, + {value: 0xa000, lo: 0x94, hi: 0x94}, + // Block 0x43, offset 0x44 + {value: 0x0173, lo: 0x0e}, + {value: 0xa000, lo: 0x83, hi: 0x83}, + {value: 0x3bca, lo: 0x84, hi: 0x84}, + {value: 0xa000, lo: 0x88, hi: 0x88}, + {value: 0x3bd1, lo: 0x89, hi: 0x89}, + {value: 0xa000, lo: 0x8b, hi: 0x8b}, + {value: 0x3bd8, lo: 0x8c, hi: 0x8c}, + {value: 0xa000, lo: 0xa3, hi: 0xa3}, + {value: 0x3bdf, lo: 0xa4, hi: 0xa4}, + {value: 0xa000, lo: 0xa5, hi: 0xa5}, + {value: 0x3be6, lo: 0xa6, hi: 0xa6}, + {value: 0x2847, lo: 0xac, hi: 0xad}, + {value: 0x284e, lo: 0xaf, hi: 0xaf}, + {value: 0x29c4, lo: 0xb0, hi: 0xb0}, + {value: 0xa000, lo: 0xbc, hi: 0xbc}, + // Block 0x44, offset 0x45 + {value: 0x0007, lo: 0x03}, + {value: 0x3c4f, lo: 0xa0, hi: 0xa1}, + {value: 0x3c79, lo: 0xa2, hi: 0xa3}, + {value: 0x3ca3, lo: 0xaa, hi: 0xad}, + // Block 0x45, offset 0x46 + {value: 0x0004, lo: 0x01}, + {value: 0x04fa, lo: 0xa9, hi: 0xaa}, + // Block 0x46, offset 0x47 + {value: 0x0002, lo: 0x03}, + {value: 0x0057, lo: 0x80, hi: 0x8f}, + {value: 0x0083, lo: 0x90, hi: 0xa9}, + {value: 0x0021, lo: 0xaa, hi: 0xaa}, + // Block 0x47, offset 0x48 + {value: 0x0000, lo: 0x01}, + {value: 0x2b50, lo: 0x8c, hi: 0x8c}, + // Block 0x48, offset 0x49 + {value: 0x0263, lo: 0x02}, + {value: 0x1ccb, lo: 0xb4, hi: 0xb4}, + {value: 0x1a6c, lo: 0xb5, hi: 0xb6}, + // Block 0x49, offset 0x4a + {value: 0x0000, lo: 0x01}, + {value: 0x44c4, lo: 0x9c, hi: 0x9c}, + // Block 0x4a, offset 0x4b + {value: 0x0000, lo: 0x02}, + {value: 0x0095, lo: 0xbc, hi: 0xbc}, + {value: 0x006d, lo: 0xbd, hi: 0xbd}, + // Block 0x4b, offset 0x4c + {value: 0x0000, lo: 0x01}, + {value: 0x8132, lo: 0xaf, hi: 0xb1}, + // Block 0x4c, offset 0x4d + {value: 0x0000, lo: 0x02}, + {value: 0x04ee, lo: 0xaf, hi: 0xaf}, + {value: 0x8104, lo: 0xbf, hi: 0xbf}, + // Block 0x4d, offset 0x4e + {value: 0x0000, lo: 0x01}, + {value: 0x8132, lo: 0xa0, hi: 0xbf}, + // Block 0x4e, offset 0x4f + {value: 0x0000, lo: 0x01}, + {value: 0x0e32, lo: 0x9f, hi: 0x9f}, + // Block 0x4f, offset 0x50 + {value: 0x0000, lo: 0x01}, + {value: 0x169a, lo: 0xb3, hi: 0xb3}, + // Block 0x50, offset 0x51 + {value: 0x0004, lo: 0x0b}, + {value: 0x1602, lo: 0x80, hi: 0x82}, + {value: 0x161a, lo: 0x83, hi: 0x83}, + {value: 0x1632, lo: 0x84, hi: 0x85}, + {value: 0x1642, lo: 0x86, hi: 0x89}, + {value: 0x1656, lo: 0x8a, hi: 0x8c}, + {value: 0x166a, lo: 0x8d, hi: 0x8d}, + {value: 0x1672, lo: 0x8e, hi: 0x8e}, + {value: 0x167a, lo: 0x8f, hi: 0x90}, + {value: 0x1686, lo: 0x91, hi: 0x93}, + {value: 0x1696, lo: 0x94, hi: 0x94}, + {value: 0x169e, lo: 0x95, hi: 0x95}, + // Block 0x51, offset 0x52 + {value: 0x0004, lo: 0x09}, + {value: 0x0001, lo: 0x80, hi: 0x80}, + {value: 0x812c, lo: 0xaa, hi: 0xaa}, + {value: 0x8131, lo: 0xab, hi: 0xab}, + {value: 0x8133, lo: 0xac, hi: 0xac}, + {value: 0x812e, lo: 0xad, hi: 0xad}, + {value: 0x812f, lo: 0xae, hi: 0xae}, + {value: 0x812f, lo: 0xaf, hi: 0xaf}, + {value: 0x0522, lo: 0xb6, hi: 0xb6}, + {value: 0x08f6, lo: 0xb8, hi: 0xba}, + // Block 0x52, offset 0x53 + {value: 0x0004, lo: 0x06}, + {value: 0x030a, lo: 0xb1, hi: 0xb2}, + {value: 0x0432, lo: 0xb3, hi: 0xb3}, + {value: 0x0312, lo: 0xb4, hi: 0xb4}, + {value: 0x0436, lo: 0xb5, hi: 0xb6}, + {value: 0x0316, lo: 0xb7, hi: 0xb9}, + {value: 0x043e, lo: 0xba, hi: 0xbf}, + // Block 0x53, offset 0x54 + {value: 0x0004, lo: 0x0c}, + {value: 0x035e, lo: 0x80, hi: 0x80}, + {value: 0x0322, lo: 0x81, hi: 0x83}, + {value: 0x0372, lo: 0x84, hi: 0x84}, + {value: 0x032e, lo: 0x85, hi: 0x8e}, + {value: 0x03be, lo: 0x8f, hi: 0xa3}, + {value: 0x03ba, lo: 0xa4, hi: 0xa4}, + {value: 0x0356, lo: 0xa5, hi: 0xa6}, + {value: 0x0456, lo: 0xa7, hi: 0xad}, + {value: 0x0362, lo: 0xae, hi: 0xae}, + {value: 0x0472, lo: 0xaf, hi: 0xb0}, + {value: 0x0366, lo: 0xb1, hi: 0xb3}, + {value: 0x0376, lo: 0xb4, hi: 0xbf}, + // Block 0x54, offset 0x55 + {value: 0x0000, lo: 0x02}, + {value: 0x8132, lo: 0xaf, hi: 0xaf}, + {value: 0x8132, lo: 0xb4, hi: 0xbd}, + // Block 0x55, offset 0x56 + {value: 0x0000, lo: 0x01}, + {value: 0x8132, lo: 0x9f, hi: 0x9f}, + // Block 0x56, offset 0x57 + {value: 0x0000, lo: 0x01}, + {value: 0x8132, lo: 0xb0, hi: 0xb1}, + // Block 0x57, offset 0x58 + {value: 0x0000, lo: 0x01}, + {value: 0x16a2, lo: 0xb0, hi: 0xb0}, + // Block 0x58, offset 0x59 + {value: 0x000c, lo: 0x01}, + {value: 0x00d7, lo: 0xb8, hi: 0xb9}, + // Block 0x59, offset 0x5a + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0x86, hi: 0x86}, + // Block 0x5a, offset 0x5b + {value: 0x0000, lo: 0x02}, + {value: 0x8104, lo: 0x84, hi: 0x84}, + {value: 0x8132, lo: 0xa0, hi: 0xb1}, + // Block 0x5b, offset 0x5c + {value: 0x0000, lo: 0x01}, + {value: 0x812d, lo: 0xab, hi: 0xad}, + // Block 0x5c, offset 0x5d + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0x93, hi: 0x93}, + // Block 0x5d, offset 0x5e + {value: 0x0000, lo: 0x01}, + {value: 0x8102, lo: 0xb3, hi: 0xb3}, + // Block 0x5e, offset 0x5f + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0x80, hi: 0x80}, + // Block 0x5f, offset 0x60 + {value: 0x0000, lo: 0x05}, + {value: 0x8132, lo: 0xb0, hi: 0xb0}, + {value: 0x8132, lo: 0xb2, hi: 0xb3}, + {value: 0x812d, lo: 0xb4, hi: 0xb4}, + {value: 0x8132, lo: 0xb7, hi: 0xb8}, + {value: 0x8132, lo: 0xbe, hi: 0xbf}, + // Block 0x60, offset 0x61 + {value: 0x0000, lo: 0x02}, + {value: 0x8132, lo: 0x81, hi: 0x81}, + {value: 0x8104, lo: 0xb6, hi: 0xb6}, + // Block 0x61, offset 0x62 + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0xad, hi: 0xad}, + // Block 0x62, offset 0x63 + {value: 0x0000, lo: 0x06}, + {value: 0xe500, lo: 0x80, hi: 0x80}, + {value: 0xc600, lo: 0x81, hi: 0x9b}, + {value: 0xe500, lo: 0x9c, hi: 0x9c}, + {value: 0xc600, lo: 0x9d, hi: 0xb7}, + {value: 0xe500, lo: 0xb8, hi: 0xb8}, + {value: 0xc600, lo: 0xb9, hi: 0xbf}, + // Block 0x63, offset 0x64 + {value: 0x0000, lo: 0x05}, + {value: 0xc600, lo: 0x80, hi: 0x93}, + {value: 0xe500, lo: 0x94, hi: 0x94}, + {value: 0xc600, lo: 0x95, hi: 0xaf}, + {value: 0xe500, lo: 0xb0, hi: 0xb0}, + {value: 0xc600, lo: 0xb1, hi: 0xbf}, + // Block 0x64, offset 0x65 + {value: 0x0000, lo: 0x05}, + {value: 0xc600, lo: 0x80, hi: 0x8b}, + {value: 0xe500, lo: 0x8c, hi: 0x8c}, + {value: 0xc600, lo: 0x8d, hi: 0xa7}, + {value: 0xe500, lo: 0xa8, hi: 0xa8}, + {value: 0xc600, lo: 0xa9, hi: 0xbf}, + // Block 0x65, offset 0x66 + {value: 0x0000, lo: 0x07}, + {value: 0xc600, lo: 0x80, hi: 0x83}, + {value: 0xe500, lo: 0x84, hi: 0x84}, + {value: 0xc600, lo: 0x85, hi: 0x9f}, + {value: 0xe500, lo: 0xa0, hi: 0xa0}, + {value: 0xc600, lo: 0xa1, hi: 0xbb}, + {value: 0xe500, lo: 0xbc, hi: 0xbc}, + {value: 0xc600, lo: 0xbd, hi: 0xbf}, + // Block 0x66, offset 0x67 + {value: 0x0000, lo: 0x05}, + {value: 0xc600, lo: 0x80, hi: 0x97}, + {value: 0xe500, lo: 0x98, hi: 0x98}, + {value: 0xc600, lo: 0x99, hi: 0xb3}, + {value: 0xe500, lo: 0xb4, hi: 0xb4}, + {value: 0xc600, lo: 0xb5, hi: 0xbf}, + // Block 0x67, offset 0x68 + {value: 0x0000, lo: 0x05}, + {value: 0xc600, lo: 0x80, hi: 0x8f}, + {value: 0xe500, lo: 0x90, hi: 0x90}, + {value: 0xc600, lo: 0x91, hi: 0xab}, + {value: 0xe500, lo: 0xac, hi: 0xac}, + {value: 0xc600, lo: 0xad, hi: 0xbf}, + // Block 0x68, offset 0x69 + {value: 0x0000, lo: 0x05}, + {value: 0xc600, lo: 0x80, hi: 0x87}, + {value: 0xe500, lo: 0x88, hi: 0x88}, + {value: 0xc600, lo: 0x89, hi: 0xa3}, + {value: 0xe500, lo: 0xa4, hi: 0xa4}, + {value: 0xc600, lo: 0xa5, hi: 0xbf}, + // Block 0x69, offset 0x6a + {value: 0x0000, lo: 0x03}, + {value: 0xc600, lo: 0x80, hi: 0x87}, + {value: 0xe500, lo: 0x88, hi: 0x88}, + {value: 0xc600, lo: 0x89, hi: 0xa3}, + // Block 0x6a, offset 0x6b + {value: 0x0002, lo: 0x01}, + {value: 0x0003, lo: 0x81, hi: 0xbf}, + // Block 0x6b, offset 0x6c + {value: 0x0004, lo: 0x0e}, + {value: 0x03be, lo: 0x82, hi: 0x87}, + {value: 0x03d6, lo: 0x8a, hi: 0x8f}, + {value: 0x03ee, lo: 0x92, hi: 0x97}, + {value: 0x0406, lo: 0x9a, hi: 0x9c}, + {value: 0x00bf, lo: 0xa0, hi: 0xa0}, + {value: 0x00c2, lo: 0xa1, hi: 0xa1}, + {value: 0x00cb, lo: 0xa2, hi: 0xa2}, + {value: 0x424b, lo: 0xa3, hi: 0xa3}, + {value: 0x00c8, lo: 0xa4, hi: 0xa4}, + {value: 0x00c5, lo: 0xa5, hi: 0xa5}, + {value: 0x04b6, lo: 0xa6, hi: 0xa6}, + {value: 0x04da, lo: 0xa8, hi: 0xa8}, + {value: 0x04ba, lo: 0xa9, hi: 0xac}, + {value: 0x04de, lo: 0xad, hi: 0xae}, + // Block 0x6c, offset 0x6d + {value: 0x0000, lo: 0x01}, + {value: 0x812d, lo: 0xbd, hi: 0xbd}, + // Block 0x6d, offset 0x6e + {value: 0x002c, lo: 0x05}, + {value: 0x812d, lo: 0x8d, hi: 0x8d}, + {value: 0x8132, lo: 0x8f, hi: 0x8f}, + {value: 0x8132, lo: 0xb8, hi: 0xb8}, + {value: 0x8101, lo: 0xb9, hi: 0xba}, + {value: 0x8104, lo: 0xbf, hi: 0xbf}, + // Block 0x6e, offset 0x6f + {value: 0x17fe, lo: 0x07}, + {value: 0xa000, lo: 0x99, hi: 0x99}, + {value: 0x421f, lo: 0x9a, hi: 0x9a}, + {value: 0xa000, lo: 0x9b, hi: 0x9b}, + {value: 0x4229, lo: 0x9c, hi: 0x9c}, + {value: 0xa000, lo: 0xa5, hi: 0xa5}, + {value: 0x4233, lo: 0xab, hi: 0xab}, + {value: 0x8104, lo: 0xb9, hi: 0xba}, + // Block 0x6f, offset 0x70 + {value: 0x0000, lo: 0x06}, + {value: 0x8132, lo: 0x80, hi: 0x82}, + {value: 0x9900, lo: 0xa7, hi: 0xa7}, + {value: 0x1990, lo: 0xae, hi: 0xae}, + {value: 0x1999, lo: 0xaf, hi: 0xaf}, + {value: 0xa000, lo: 0xb1, hi: 0xb2}, + {value: 0x8104, lo: 0xb3, hi: 0xb4}, + // Block 0x70, offset 0x71 + {value: 0x0000, lo: 0x02}, + {value: 0x8104, lo: 0xb6, hi: 0xb6}, + {value: 0x8102, lo: 0xb7, hi: 0xb7}, + // Block 0x71, offset 0x72 + {value: 0x0000, lo: 0x0c}, + {value: 0x45b3, lo: 0x9e, hi: 0x9e}, + {value: 0x45bd, lo: 0x9f, hi: 0x9f}, + {value: 0x45f1, lo: 0xa0, hi: 0xa0}, + {value: 0x45ff, lo: 0xa1, hi: 0xa1}, + {value: 0x460d, lo: 0xa2, hi: 0xa2}, + {value: 0x461b, lo: 0xa3, hi: 0xa3}, + {value: 0x4629, lo: 0xa4, hi: 0xa4}, + {value: 0x812b, lo: 0xa5, hi: 0xa6}, + {value: 0x8101, lo: 0xa7, hi: 0xa9}, + {value: 0x8130, lo: 0xad, hi: 0xad}, + {value: 0x812b, lo: 0xae, hi: 0xb2}, + {value: 0x812d, lo: 0xbb, hi: 0xbf}, + // Block 0x72, offset 0x73 + {value: 0x0000, lo: 0x09}, + {value: 0x812d, lo: 0x80, hi: 0x82}, + {value: 0x8132, lo: 0x85, hi: 0x89}, + {value: 0x812d, lo: 0x8a, hi: 0x8b}, + {value: 0x8132, lo: 0xaa, hi: 0xad}, + {value: 0x45c7, lo: 0xbb, hi: 0xbb}, + {value: 0x45d1, lo: 0xbc, hi: 0xbc}, + {value: 0x4637, lo: 0xbd, hi: 0xbd}, + {value: 0x4653, lo: 0xbe, hi: 0xbe}, + {value: 0x4645, lo: 0xbf, hi: 0xbf}, + // Block 0x73, offset 0x74 + {value: 0x0000, lo: 0x01}, + {value: 0x4661, lo: 0x80, hi: 0x80}, + // Block 0x74, offset 0x75 + {value: 0x0000, lo: 0x01}, + {value: 0x8132, lo: 0x82, hi: 0x84}, + // Block 0x75, offset 0x76 + {value: 0x0002, lo: 0x03}, + {value: 0x0043, lo: 0x80, hi: 0x99}, + {value: 0x0083, lo: 0x9a, hi: 0xb3}, + {value: 0x0043, lo: 0xb4, hi: 0xbf}, + // Block 0x76, offset 0x77 + {value: 0x0002, lo: 0x04}, + {value: 0x005b, lo: 0x80, hi: 0x8d}, + {value: 0x0083, lo: 0x8e, hi: 0x94}, + {value: 0x0093, lo: 0x96, hi: 0xa7}, + {value: 0x0043, lo: 0xa8, hi: 0xbf}, + // Block 0x77, offset 0x78 + {value: 0x0002, lo: 0x0b}, + {value: 0x0073, lo: 0x80, hi: 0x81}, + {value: 0x0083, lo: 0x82, hi: 0x9b}, + {value: 0x0043, lo: 0x9c, hi: 0x9c}, + {value: 0x0047, lo: 0x9e, hi: 0x9f}, + {value: 0x004f, lo: 0xa2, hi: 0xa2}, + {value: 0x0055, lo: 0xa5, hi: 0xa6}, + {value: 0x005d, lo: 0xa9, hi: 0xac}, + {value: 0x0067, lo: 0xae, hi: 0xb5}, + {value: 0x0083, lo: 0xb6, hi: 0xb9}, + {value: 0x008d, lo: 0xbb, hi: 0xbb}, + {value: 0x0091, lo: 0xbd, hi: 0xbf}, + // Block 0x78, offset 0x79 + {value: 0x0002, lo: 0x04}, + {value: 0x0097, lo: 0x80, hi: 0x83}, + {value: 0x00a1, lo: 0x85, hi: 0x8f}, + {value: 0x0043, lo: 0x90, hi: 0xa9}, + {value: 0x0083, lo: 0xaa, hi: 0xbf}, + // Block 0x79, offset 0x7a + {value: 0x0002, lo: 0x08}, + {value: 0x00af, lo: 0x80, hi: 0x83}, + {value: 0x0043, lo: 0x84, hi: 0x85}, + {value: 0x0049, lo: 0x87, hi: 0x8a}, + {value: 0x0055, lo: 0x8d, hi: 0x94}, + {value: 0x0067, lo: 0x96, hi: 0x9c}, + {value: 0x0083, lo: 0x9e, hi: 0xb7}, + {value: 0x0043, lo: 0xb8, hi: 0xb9}, + {value: 0x0049, lo: 0xbb, hi: 0xbe}, + // Block 0x7a, offset 0x7b + {value: 0x0002, lo: 0x05}, + {value: 0x0053, lo: 0x80, hi: 0x84}, + {value: 0x005f, lo: 0x86, hi: 0x86}, + {value: 0x0067, lo: 0x8a, hi: 0x90}, + {value: 0x0083, lo: 0x92, hi: 0xab}, + {value: 0x0043, lo: 0xac, hi: 0xbf}, + // Block 0x7b, offset 0x7c + {value: 0x0002, lo: 0x04}, + {value: 0x006b, lo: 0x80, hi: 0x85}, + {value: 0x0083, lo: 0x86, hi: 0x9f}, + {value: 0x0043, lo: 0xa0, hi: 0xb9}, + {value: 0x0083, lo: 0xba, hi: 0xbf}, + // Block 0x7c, offset 0x7d + {value: 0x0002, lo: 0x03}, + {value: 0x008f, lo: 0x80, hi: 0x93}, + {value: 0x0043, lo: 0x94, hi: 0xad}, + {value: 0x0083, lo: 0xae, hi: 0xbf}, + // Block 0x7d, offset 0x7e + {value: 0x0002, lo: 0x04}, + {value: 0x00a7, lo: 0x80, hi: 0x87}, + {value: 0x0043, lo: 0x88, hi: 0xa1}, + {value: 0x0083, lo: 0xa2, hi: 0xbb}, + {value: 0x0043, lo: 0xbc, hi: 0xbf}, + // Block 0x7e, offset 0x7f + {value: 0x0002, lo: 0x03}, + {value: 0x004b, lo: 0x80, hi: 0x95}, + {value: 0x0083, lo: 0x96, hi: 0xaf}, + {value: 0x0043, lo: 0xb0, hi: 0xbf}, + // Block 0x7f, offset 0x80 + {value: 0x0003, lo: 0x0f}, + {value: 0x01b5, lo: 0x80, hi: 0x80}, + {value: 0x04ce, lo: 0x81, hi: 0x81}, + {value: 0x01b8, lo: 0x82, hi: 0x9a}, + {value: 0x04ca, lo: 0x9b, hi: 0x9b}, + {value: 0x01c4, lo: 0x9c, hi: 0x9c}, + {value: 0x01cd, lo: 0x9d, hi: 0x9d}, + {value: 0x01d3, lo: 0x9e, hi: 0x9e}, + {value: 0x01f7, lo: 0x9f, hi: 0x9f}, + {value: 0x01e8, lo: 0xa0, hi: 0xa0}, + {value: 0x01e5, lo: 0xa1, hi: 0xa1}, + {value: 0x0170, lo: 0xa2, hi: 0xb2}, + {value: 0x0185, lo: 0xb3, hi: 0xb3}, + {value: 0x01a3, lo: 0xb4, hi: 0xba}, + {value: 0x04ce, lo: 0xbb, hi: 0xbb}, + {value: 0x01b8, lo: 0xbc, hi: 0xbf}, + // Block 0x80, offset 0x81 + {value: 0x0003, lo: 0x0d}, + {value: 0x01c4, lo: 0x80, hi: 0x94}, + {value: 0x04ca, lo: 0x95, hi: 0x95}, + {value: 0x01c4, lo: 0x96, hi: 0x96}, + {value: 0x01cd, lo: 0x97, hi: 0x97}, + {value: 0x01d3, lo: 0x98, hi: 0x98}, + {value: 0x01f7, lo: 0x99, hi: 0x99}, + {value: 0x01e8, lo: 0x9a, hi: 0x9a}, + {value: 0x01e5, lo: 0x9b, hi: 0x9b}, + {value: 0x0170, lo: 0x9c, hi: 0xac}, + {value: 0x0185, lo: 0xad, hi: 0xad}, + {value: 0x01a3, lo: 0xae, hi: 0xb4}, + {value: 0x04ce, lo: 0xb5, hi: 0xb5}, + {value: 0x01b8, lo: 0xb6, hi: 0xbf}, + // Block 0x81, offset 0x82 + {value: 0x0003, lo: 0x0d}, + {value: 0x01d6, lo: 0x80, hi: 0x8e}, + {value: 0x04ca, lo: 0x8f, hi: 0x8f}, + {value: 0x01c4, lo: 0x90, hi: 0x90}, + {value: 0x01cd, lo: 0x91, hi: 0x91}, + {value: 0x01d3, lo: 0x92, hi: 0x92}, + {value: 0x01f7, lo: 0x93, hi: 0x93}, + {value: 0x01e8, lo: 0x94, hi: 0x94}, + {value: 0x01e5, lo: 0x95, hi: 0x95}, + {value: 0x0170, lo: 0x96, hi: 0xa6}, + {value: 0x0185, lo: 0xa7, hi: 0xa7}, + {value: 0x01a3, lo: 0xa8, hi: 0xae}, + {value: 0x04ce, lo: 0xaf, hi: 0xaf}, + {value: 0x01b8, lo: 0xb0, hi: 0xbf}, + // Block 0x82, offset 0x83 + {value: 0x0003, lo: 0x0d}, + {value: 0x01e8, lo: 0x80, hi: 0x88}, + {value: 0x04ca, lo: 0x89, hi: 0x89}, + {value: 0x01c4, lo: 0x8a, hi: 0x8a}, + {value: 0x01cd, lo: 0x8b, hi: 0x8b}, + {value: 0x01d3, lo: 0x8c, hi: 0x8c}, + {value: 0x01f7, lo: 0x8d, hi: 0x8d}, + {value: 0x01e8, lo: 0x8e, hi: 0x8e}, + {value: 0x01e5, lo: 0x8f, hi: 0x8f}, + {value: 0x0170, lo: 0x90, hi: 0xa0}, + {value: 0x0185, lo: 0xa1, hi: 0xa1}, + {value: 0x01a3, lo: 0xa2, hi: 0xa8}, + {value: 0x04ce, lo: 0xa9, hi: 0xa9}, + {value: 0x01b8, lo: 0xaa, hi: 0xbf}, + // Block 0x83, offset 0x84 + {value: 0x0002, lo: 0x09}, + {value: 0x0063, lo: 0x80, hi: 0x89}, + {value: 0x1a90, lo: 0x8a, hi: 0x8a}, + {value: 0x1ac0, lo: 0x8b, hi: 0x8b}, + {value: 0x1adb, lo: 0x8c, hi: 0x8c}, + {value: 0x1ae1, lo: 0x8d, hi: 0x8d}, + {value: 0x1cff, lo: 0x8e, hi: 0x8e}, + {value: 0x1aed, lo: 0x8f, hi: 0x8f}, + {value: 0x1aba, lo: 0xaa, hi: 0xaa}, + {value: 0x1abd, lo: 0xab, hi: 0xab}, + // Block 0x84, offset 0x85 + {value: 0x0000, lo: 0x01}, + {value: 0x1a7e, lo: 0x90, hi: 0x90}, + // Block 0x85, offset 0x86 + {value: 0x0028, lo: 0x09}, + {value: 0x2a0a, lo: 0x80, hi: 0x80}, + {value: 0x29ce, lo: 0x81, hi: 0x81}, + {value: 0x29d8, lo: 0x82, hi: 0x82}, + {value: 0x29ec, lo: 0x83, hi: 0x84}, + {value: 0x29f6, lo: 0x85, hi: 0x86}, + {value: 0x29e2, lo: 0x87, hi: 0x87}, + {value: 0x2a00, lo: 0x88, hi: 0x88}, + {value: 0x0bde, lo: 0x90, hi: 0x90}, + {value: 0x0956, lo: 0x91, hi: 0x91}, +} + +// nfkcLookup: 1280 bytes +// Block 0 is the null block. +var nfkcLookup = [1280]uint8{ + // Block 0x0, offset 0x0 + // Block 0x1, offset 0x40 + // Block 0x2, offset 0x80 + // Block 0x3, offset 0xc0 + 0x0c2: 0x58, 0x0c3: 0x01, 0x0c4: 0x02, 0x0c5: 0x03, 0x0c6: 0x59, 0x0c7: 0x04, + 0x0c8: 0x05, 0x0ca: 0x5a, 0x0cb: 0x5b, 0x0cc: 0x06, 0x0cd: 0x07, 0x0ce: 0x08, 0x0cf: 0x09, + 0x0d0: 0x0a, 0x0d1: 0x5c, 0x0d2: 0x5d, 0x0d3: 0x0b, 0x0d6: 0x0c, 0x0d7: 0x5e, + 0x0d8: 0x5f, 0x0d9: 0x0d, 0x0db: 0x60, 0x0dc: 0x61, 0x0dd: 0x62, 0x0df: 0x63, + 0x0e0: 0x02, 0x0e1: 0x03, 0x0e2: 0x04, 0x0e3: 0x05, + 0x0ea: 0x06, 0x0eb: 0x07, 0x0ec: 0x08, 0x0ed: 0x09, 0x0ef: 0x0a, + 0x0f0: 0x11, + // Block 0x4, offset 0x100 + 0x120: 0x64, 0x121: 0x65, 0x123: 0x66, 0x124: 0x67, 0x125: 0x68, 0x126: 0x69, 0x127: 0x6a, + 0x128: 0x6b, 0x129: 0x6c, 0x12a: 0x6d, 0x12b: 0x6e, 0x12c: 0x69, 0x12d: 0x6f, 0x12e: 0x70, 0x12f: 0x71, + 0x131: 0x72, 0x132: 0x73, 0x133: 0x74, 0x134: 0x75, 0x135: 0x76, 0x137: 0x77, + 0x138: 0x78, 0x139: 0x79, 0x13a: 0x7a, 0x13b: 0x7b, 0x13c: 0x7c, 0x13d: 0x7d, 0x13e: 0x7e, 0x13f: 0x7f, + // Block 0x5, offset 0x140 + 0x140: 0x80, 0x142: 0x81, 0x143: 0x82, 0x144: 0x83, 0x145: 0x84, 0x146: 0x85, 0x147: 0x86, + 0x14d: 0x87, + 0x15c: 0x88, 0x15f: 0x89, + 0x162: 0x8a, 0x164: 0x8b, + 0x168: 0x8c, 0x169: 0x8d, 0x16c: 0x0e, 0x16d: 0x8e, 0x16e: 0x8f, 0x16f: 0x90, + 0x170: 0x91, 0x173: 0x92, 0x174: 0x93, 0x175: 0x0f, 0x176: 0x10, 0x177: 0x94, + 0x178: 0x11, 0x179: 0x12, 0x17a: 0x13, 0x17b: 0x14, 0x17c: 0x15, 0x17d: 0x16, 0x17e: 0x17, 0x17f: 0x18, + // Block 0x6, offset 0x180 + 0x180: 0x95, 0x181: 0x96, 0x182: 0x97, 0x183: 0x98, 0x184: 0x19, 0x185: 0x1a, 0x186: 0x99, 0x187: 0x9a, + 0x188: 0x9b, 0x189: 0x1b, 0x18a: 0x1c, 0x18b: 0x9c, 0x18c: 0x9d, + 0x191: 0x1d, 0x192: 0x1e, 0x193: 0x9e, + 0x1a8: 0x9f, 0x1a9: 0xa0, 0x1ab: 0xa1, + 0x1b1: 0xa2, 0x1b3: 0xa3, 0x1b5: 0xa4, 0x1b7: 0xa5, + 0x1ba: 0xa6, 0x1bb: 0xa7, 0x1bc: 0x1f, 0x1bd: 0x20, 0x1be: 0x21, 0x1bf: 0xa8, + // Block 0x7, offset 0x1c0 + 0x1c0: 0xa9, 0x1c1: 0x22, 0x1c2: 0x23, 0x1c3: 0x24, 0x1c4: 0xaa, 0x1c5: 0xab, 0x1c6: 0x25, + 0x1c8: 0x26, 0x1c9: 0x27, 0x1ca: 0x28, 0x1cb: 0x29, 0x1cc: 0x2a, 0x1cd: 0x2b, 0x1ce: 0x2c, 0x1cf: 0x2d, + // Block 0x8, offset 0x200 + 0x219: 0xac, 0x21a: 0xad, 0x21b: 0xae, 0x21d: 0xaf, 0x21f: 0xb0, + 0x220: 0xb1, 0x223: 0xb2, 0x224: 0xb3, 0x225: 0xb4, 0x226: 0xb5, 0x227: 0xb6, + 0x22a: 0xb7, 0x22b: 0xb8, 0x22f: 0xb9, + 0x230: 0xba, 0x231: 0xbb, 0x232: 0xbc, 0x233: 0xbd, 0x234: 0xbe, 0x235: 0xbf, 0x236: 0xc0, 0x237: 0xba, + 0x238: 0xbb, 0x239: 0xbc, 0x23a: 0xbd, 0x23b: 0xbe, 0x23c: 0xbf, 0x23d: 0xc0, 0x23e: 0xba, 0x23f: 0xbb, + // Block 0x9, offset 0x240 + 0x240: 0xbc, 0x241: 0xbd, 0x242: 0xbe, 0x243: 0xbf, 0x244: 0xc0, 0x245: 0xba, 0x246: 0xbb, 0x247: 0xbc, + 0x248: 0xbd, 0x249: 0xbe, 0x24a: 0xbf, 0x24b: 0xc0, 0x24c: 0xba, 0x24d: 0xbb, 0x24e: 0xbc, 0x24f: 0xbd, + 0x250: 0xbe, 0x251: 0xbf, 0x252: 0xc0, 0x253: 0xba, 0x254: 0xbb, 0x255: 0xbc, 0x256: 0xbd, 0x257: 0xbe, + 0x258: 0xbf, 0x259: 0xc0, 0x25a: 0xba, 0x25b: 0xbb, 0x25c: 0xbc, 0x25d: 0xbd, 0x25e: 0xbe, 0x25f: 0xbf, + 0x260: 0xc0, 0x261: 0xba, 0x262: 0xbb, 0x263: 0xbc, 0x264: 0xbd, 0x265: 0xbe, 0x266: 0xbf, 0x267: 0xc0, + 0x268: 0xba, 0x269: 0xbb, 0x26a: 0xbc, 0x26b: 0xbd, 0x26c: 0xbe, 0x26d: 0xbf, 0x26e: 0xc0, 0x26f: 0xba, + 0x270: 0xbb, 0x271: 0xbc, 0x272: 0xbd, 0x273: 0xbe, 0x274: 0xbf, 0x275: 0xc0, 0x276: 0xba, 0x277: 0xbb, + 0x278: 0xbc, 0x279: 0xbd, 0x27a: 0xbe, 0x27b: 0xbf, 0x27c: 0xc0, 0x27d: 0xba, 0x27e: 0xbb, 0x27f: 0xbc, + // Block 0xa, offset 0x280 + 0x280: 0xbd, 0x281: 0xbe, 0x282: 0xbf, 0x283: 0xc0, 0x284: 0xba, 0x285: 0xbb, 0x286: 0xbc, 0x287: 0xbd, + 0x288: 0xbe, 0x289: 0xbf, 0x28a: 0xc0, 0x28b: 0xba, 0x28c: 0xbb, 0x28d: 0xbc, 0x28e: 0xbd, 0x28f: 0xbe, + 0x290: 0xbf, 0x291: 0xc0, 0x292: 0xba, 0x293: 0xbb, 0x294: 0xbc, 0x295: 0xbd, 0x296: 0xbe, 0x297: 0xbf, + 0x298: 0xc0, 0x299: 0xba, 0x29a: 0xbb, 0x29b: 0xbc, 0x29c: 0xbd, 0x29d: 0xbe, 0x29e: 0xbf, 0x29f: 0xc0, + 0x2a0: 0xba, 0x2a1: 0xbb, 0x2a2: 0xbc, 0x2a3: 0xbd, 0x2a4: 0xbe, 0x2a5: 0xbf, 0x2a6: 0xc0, 0x2a7: 0xba, + 0x2a8: 0xbb, 0x2a9: 0xbc, 0x2aa: 0xbd, 0x2ab: 0xbe, 0x2ac: 0xbf, 0x2ad: 0xc0, 0x2ae: 0xba, 0x2af: 0xbb, + 0x2b0: 0xbc, 0x2b1: 0xbd, 0x2b2: 0xbe, 0x2b3: 0xbf, 0x2b4: 0xc0, 0x2b5: 0xba, 0x2b6: 0xbb, 0x2b7: 0xbc, + 0x2b8: 0xbd, 0x2b9: 0xbe, 0x2ba: 0xbf, 0x2bb: 0xc0, 0x2bc: 0xba, 0x2bd: 0xbb, 0x2be: 0xbc, 0x2bf: 0xbd, + // Block 0xb, offset 0x2c0 + 0x2c0: 0xbe, 0x2c1: 0xbf, 0x2c2: 0xc0, 0x2c3: 0xba, 0x2c4: 0xbb, 0x2c5: 0xbc, 0x2c6: 0xbd, 0x2c7: 0xbe, + 0x2c8: 0xbf, 0x2c9: 0xc0, 0x2ca: 0xba, 0x2cb: 0xbb, 0x2cc: 0xbc, 0x2cd: 0xbd, 0x2ce: 0xbe, 0x2cf: 0xbf, + 0x2d0: 0xc0, 0x2d1: 0xba, 0x2d2: 0xbb, 0x2d3: 0xbc, 0x2d4: 0xbd, 0x2d5: 0xbe, 0x2d6: 0xbf, 0x2d7: 0xc0, + 0x2d8: 0xba, 0x2d9: 0xbb, 0x2da: 0xbc, 0x2db: 0xbd, 0x2dc: 0xbe, 0x2dd: 0xbf, 0x2de: 0xc1, + // Block 0xc, offset 0x300 + 0x324: 0x2e, 0x325: 0x2f, 0x326: 0x30, 0x327: 0x31, + 0x328: 0x32, 0x329: 0x33, 0x32a: 0x34, 0x32b: 0x35, 0x32c: 0x36, 0x32d: 0x37, 0x32e: 0x38, 0x32f: 0x39, + 0x330: 0x3a, 0x331: 0x3b, 0x332: 0x3c, 0x333: 0x3d, 0x334: 0x3e, 0x335: 0x3f, 0x336: 0x40, 0x337: 0x41, + 0x338: 0x42, 0x339: 0x43, 0x33a: 0x44, 0x33b: 0x45, 0x33c: 0xc2, 0x33d: 0x46, 0x33e: 0x47, 0x33f: 0xc3, + // Block 0xd, offset 0x340 + 0x347: 0xc4, + 0x368: 0xc5, + // Block 0xe, offset 0x380 + 0x381: 0xb1, 0x382: 0xc6, 0x384: 0xc7, 0x387: 0xb6, + 0x39a: 0xc8, + // Block 0xf, offset 0x3c0 + 0x3c5: 0xc9, 0x3c6: 0xca, 0x3c7: 0xcb, + 0x3c9: 0xcc, + 0x3d0: 0xcd, 0x3d1: 0xce, 0x3d2: 0xcf, 0x3d3: 0xd0, 0x3d4: 0xd1, 0x3d5: 0xd2, 0x3d6: 0xd3, 0x3d7: 0xd4, + 0x3d8: 0xd5, 0x3d9: 0xd6, 0x3da: 0x48, 0x3db: 0xd7, 0x3dc: 0xd8, 0x3dd: 0xd9, 0x3de: 0xda, 0x3df: 0x49, + // Block 0x10, offset 0x400 + 0x438: 0x4a, 0x439: 0x4b, 0x43a: 0x4c, + // Block 0x11, offset 0x440 + 0x444: 0x4d, 0x445: 0xdb, 0x446: 0xdc, + 0x448: 0x4e, 0x449: 0xdd, + // Block 0x12, offset 0x480 + 0x4a0: 0x4f, 0x4a1: 0x50, 0x4a2: 0x51, 0x4a3: 0x52, 0x4a4: 0x53, 0x4a5: 0x54, 0x4a6: 0x55, 0x4a7: 0x56, + 0x4a8: 0x57, + // Block 0x13, offset 0x4c0 + 0x4d0: 0x0b, 0x4d1: 0x0c, + 0x4dd: 0x0d, 0x4de: 0x0e, 0x4df: 0x0f, + 0x4ef: 0x10, +} + +var nfkcTrie = trie{nfkcLookup[:], nfkcValues[:], nfkcSparseValues[:], nfkcSparseOffset[:], 88} + +// recompMap: 7464 bytes (entries only) +var recompMap = map[uint32]rune{ + 0x00410300: 0x00C0, + 0x00410301: 0x00C1, + 0x00410302: 0x00C2, + 0x00410303: 0x00C3, + 0x00410308: 0x00C4, + 0x0041030A: 0x00C5, + 0x00430327: 0x00C7, + 0x00450300: 0x00C8, + 0x00450301: 0x00C9, + 0x00450302: 0x00CA, + 0x00450308: 0x00CB, + 0x00490300: 0x00CC, + 0x00490301: 0x00CD, + 0x00490302: 0x00CE, + 0x00490308: 0x00CF, + 0x004E0303: 0x00D1, + 0x004F0300: 0x00D2, + 0x004F0301: 0x00D3, + 0x004F0302: 0x00D4, + 0x004F0303: 0x00D5, + 0x004F0308: 0x00D6, + 0x00550300: 0x00D9, + 0x00550301: 0x00DA, + 0x00550302: 0x00DB, + 0x00550308: 0x00DC, + 0x00590301: 0x00DD, + 0x00610300: 0x00E0, + 0x00610301: 0x00E1, + 0x00610302: 0x00E2, + 0x00610303: 0x00E3, + 0x00610308: 0x00E4, + 0x0061030A: 0x00E5, + 0x00630327: 0x00E7, + 0x00650300: 0x00E8, + 0x00650301: 0x00E9, + 0x00650302: 0x00EA, + 0x00650308: 0x00EB, + 0x00690300: 0x00EC, + 0x00690301: 0x00ED, + 0x00690302: 0x00EE, + 0x00690308: 0x00EF, + 0x006E0303: 0x00F1, + 0x006F0300: 0x00F2, + 0x006F0301: 0x00F3, + 0x006F0302: 0x00F4, + 0x006F0303: 0x00F5, + 0x006F0308: 0x00F6, + 0x00750300: 0x00F9, + 0x00750301: 0x00FA, + 0x00750302: 0x00FB, + 0x00750308: 0x00FC, + 0x00790301: 0x00FD, + 0x00790308: 0x00FF, + 0x00410304: 0x0100, + 0x00610304: 0x0101, + 0x00410306: 0x0102, + 0x00610306: 0x0103, + 0x00410328: 0x0104, + 0x00610328: 0x0105, + 0x00430301: 0x0106, + 0x00630301: 0x0107, + 0x00430302: 0x0108, + 0x00630302: 0x0109, + 0x00430307: 0x010A, + 0x00630307: 0x010B, + 0x0043030C: 0x010C, + 0x0063030C: 0x010D, + 0x0044030C: 0x010E, + 0x0064030C: 0x010F, + 0x00450304: 0x0112, + 0x00650304: 0x0113, + 0x00450306: 0x0114, + 0x00650306: 0x0115, + 0x00450307: 0x0116, + 0x00650307: 0x0117, + 0x00450328: 0x0118, + 0x00650328: 0x0119, + 0x0045030C: 0x011A, + 0x0065030C: 0x011B, + 0x00470302: 0x011C, + 0x00670302: 0x011D, + 0x00470306: 0x011E, + 0x00670306: 0x011F, + 0x00470307: 0x0120, + 0x00670307: 0x0121, + 0x00470327: 0x0122, + 0x00670327: 0x0123, + 0x00480302: 0x0124, + 0x00680302: 0x0125, + 0x00490303: 0x0128, + 0x00690303: 0x0129, + 0x00490304: 0x012A, + 0x00690304: 0x012B, + 0x00490306: 0x012C, + 0x00690306: 0x012D, + 0x00490328: 0x012E, + 0x00690328: 0x012F, + 0x00490307: 0x0130, + 0x004A0302: 0x0134, + 0x006A0302: 0x0135, + 0x004B0327: 0x0136, + 0x006B0327: 0x0137, + 0x004C0301: 0x0139, + 0x006C0301: 0x013A, + 0x004C0327: 0x013B, + 0x006C0327: 0x013C, + 0x004C030C: 0x013D, + 0x006C030C: 0x013E, + 0x004E0301: 0x0143, + 0x006E0301: 0x0144, + 0x004E0327: 0x0145, + 0x006E0327: 0x0146, + 0x004E030C: 0x0147, + 0x006E030C: 0x0148, + 0x004F0304: 0x014C, + 0x006F0304: 0x014D, + 0x004F0306: 0x014E, + 0x006F0306: 0x014F, + 0x004F030B: 0x0150, + 0x006F030B: 0x0151, + 0x00520301: 0x0154, + 0x00720301: 0x0155, + 0x00520327: 0x0156, + 0x00720327: 0x0157, + 0x0052030C: 0x0158, + 0x0072030C: 0x0159, + 0x00530301: 0x015A, + 0x00730301: 0x015B, + 0x00530302: 0x015C, + 0x00730302: 0x015D, + 0x00530327: 0x015E, + 0x00730327: 0x015F, + 0x0053030C: 0x0160, + 0x0073030C: 0x0161, + 0x00540327: 0x0162, + 0x00740327: 0x0163, + 0x0054030C: 0x0164, + 0x0074030C: 0x0165, + 0x00550303: 0x0168, + 0x00750303: 0x0169, + 0x00550304: 0x016A, + 0x00750304: 0x016B, + 0x00550306: 0x016C, + 0x00750306: 0x016D, + 0x0055030A: 0x016E, + 0x0075030A: 0x016F, + 0x0055030B: 0x0170, + 0x0075030B: 0x0171, + 0x00550328: 0x0172, + 0x00750328: 0x0173, + 0x00570302: 0x0174, + 0x00770302: 0x0175, + 0x00590302: 0x0176, + 0x00790302: 0x0177, + 0x00590308: 0x0178, + 0x005A0301: 0x0179, + 0x007A0301: 0x017A, + 0x005A0307: 0x017B, + 0x007A0307: 0x017C, + 0x005A030C: 0x017D, + 0x007A030C: 0x017E, + 0x004F031B: 0x01A0, + 0x006F031B: 0x01A1, + 0x0055031B: 0x01AF, + 0x0075031B: 0x01B0, + 0x0041030C: 0x01CD, + 0x0061030C: 0x01CE, + 0x0049030C: 0x01CF, + 0x0069030C: 0x01D0, + 0x004F030C: 0x01D1, + 0x006F030C: 0x01D2, + 0x0055030C: 0x01D3, + 0x0075030C: 0x01D4, + 0x00DC0304: 0x01D5, + 0x00FC0304: 0x01D6, + 0x00DC0301: 0x01D7, + 0x00FC0301: 0x01D8, + 0x00DC030C: 0x01D9, + 0x00FC030C: 0x01DA, + 0x00DC0300: 0x01DB, + 0x00FC0300: 0x01DC, + 0x00C40304: 0x01DE, + 0x00E40304: 0x01DF, + 0x02260304: 0x01E0, + 0x02270304: 0x01E1, + 0x00C60304: 0x01E2, + 0x00E60304: 0x01E3, + 0x0047030C: 0x01E6, + 0x0067030C: 0x01E7, + 0x004B030C: 0x01E8, + 0x006B030C: 0x01E9, + 0x004F0328: 0x01EA, + 0x006F0328: 0x01EB, + 0x01EA0304: 0x01EC, + 0x01EB0304: 0x01ED, + 0x01B7030C: 0x01EE, + 0x0292030C: 0x01EF, + 0x006A030C: 0x01F0, + 0x00470301: 0x01F4, + 0x00670301: 0x01F5, + 0x004E0300: 0x01F8, + 0x006E0300: 0x01F9, + 0x00C50301: 0x01FA, + 0x00E50301: 0x01FB, + 0x00C60301: 0x01FC, + 0x00E60301: 0x01FD, + 0x00D80301: 0x01FE, + 0x00F80301: 0x01FF, + 0x0041030F: 0x0200, + 0x0061030F: 0x0201, + 0x00410311: 0x0202, + 0x00610311: 0x0203, + 0x0045030F: 0x0204, + 0x0065030F: 0x0205, + 0x00450311: 0x0206, + 0x00650311: 0x0207, + 0x0049030F: 0x0208, + 0x0069030F: 0x0209, + 0x00490311: 0x020A, + 0x00690311: 0x020B, + 0x004F030F: 0x020C, + 0x006F030F: 0x020D, + 0x004F0311: 0x020E, + 0x006F0311: 0x020F, + 0x0052030F: 0x0210, + 0x0072030F: 0x0211, + 0x00520311: 0x0212, + 0x00720311: 0x0213, + 0x0055030F: 0x0214, + 0x0075030F: 0x0215, + 0x00550311: 0x0216, + 0x00750311: 0x0217, + 0x00530326: 0x0218, + 0x00730326: 0x0219, + 0x00540326: 0x021A, + 0x00740326: 0x021B, + 0x0048030C: 0x021E, + 0x0068030C: 0x021F, + 0x00410307: 0x0226, + 0x00610307: 0x0227, + 0x00450327: 0x0228, + 0x00650327: 0x0229, + 0x00D60304: 0x022A, + 0x00F60304: 0x022B, + 0x00D50304: 0x022C, + 0x00F50304: 0x022D, + 0x004F0307: 0x022E, + 0x006F0307: 0x022F, + 0x022E0304: 0x0230, + 0x022F0304: 0x0231, + 0x00590304: 0x0232, + 0x00790304: 0x0233, + 0x00A80301: 0x0385, + 0x03910301: 0x0386, + 0x03950301: 0x0388, + 0x03970301: 0x0389, + 0x03990301: 0x038A, + 0x039F0301: 0x038C, + 0x03A50301: 0x038E, + 0x03A90301: 0x038F, + 0x03CA0301: 0x0390, + 0x03990308: 0x03AA, + 0x03A50308: 0x03AB, + 0x03B10301: 0x03AC, + 0x03B50301: 0x03AD, + 0x03B70301: 0x03AE, + 0x03B90301: 0x03AF, + 0x03CB0301: 0x03B0, + 0x03B90308: 0x03CA, + 0x03C50308: 0x03CB, + 0x03BF0301: 0x03CC, + 0x03C50301: 0x03CD, + 0x03C90301: 0x03CE, + 0x03D20301: 0x03D3, + 0x03D20308: 0x03D4, + 0x04150300: 0x0400, + 0x04150308: 0x0401, + 0x04130301: 0x0403, + 0x04060308: 0x0407, + 0x041A0301: 0x040C, + 0x04180300: 0x040D, + 0x04230306: 0x040E, + 0x04180306: 0x0419, + 0x04380306: 0x0439, + 0x04350300: 0x0450, + 0x04350308: 0x0451, + 0x04330301: 0x0453, + 0x04560308: 0x0457, + 0x043A0301: 0x045C, + 0x04380300: 0x045D, + 0x04430306: 0x045E, + 0x0474030F: 0x0476, + 0x0475030F: 0x0477, + 0x04160306: 0x04C1, + 0x04360306: 0x04C2, + 0x04100306: 0x04D0, + 0x04300306: 0x04D1, + 0x04100308: 0x04D2, + 0x04300308: 0x04D3, + 0x04150306: 0x04D6, + 0x04350306: 0x04D7, + 0x04D80308: 0x04DA, + 0x04D90308: 0x04DB, + 0x04160308: 0x04DC, + 0x04360308: 0x04DD, + 0x04170308: 0x04DE, + 0x04370308: 0x04DF, + 0x04180304: 0x04E2, + 0x04380304: 0x04E3, + 0x04180308: 0x04E4, + 0x04380308: 0x04E5, + 0x041E0308: 0x04E6, + 0x043E0308: 0x04E7, + 0x04E80308: 0x04EA, + 0x04E90308: 0x04EB, + 0x042D0308: 0x04EC, + 0x044D0308: 0x04ED, + 0x04230304: 0x04EE, + 0x04430304: 0x04EF, + 0x04230308: 0x04F0, + 0x04430308: 0x04F1, + 0x0423030B: 0x04F2, + 0x0443030B: 0x04F3, + 0x04270308: 0x04F4, + 0x04470308: 0x04F5, + 0x042B0308: 0x04F8, + 0x044B0308: 0x04F9, + 0x06270653: 0x0622, + 0x06270654: 0x0623, + 0x06480654: 0x0624, + 0x06270655: 0x0625, + 0x064A0654: 0x0626, + 0x06D50654: 0x06C0, + 0x06C10654: 0x06C2, + 0x06D20654: 0x06D3, + 0x0928093C: 0x0929, + 0x0930093C: 0x0931, + 0x0933093C: 0x0934, + 0x09C709BE: 0x09CB, + 0x09C709D7: 0x09CC, + 0x0B470B56: 0x0B48, + 0x0B470B3E: 0x0B4B, + 0x0B470B57: 0x0B4C, + 0x0B920BD7: 0x0B94, + 0x0BC60BBE: 0x0BCA, + 0x0BC70BBE: 0x0BCB, + 0x0BC60BD7: 0x0BCC, + 0x0C460C56: 0x0C48, + 0x0CBF0CD5: 0x0CC0, + 0x0CC60CD5: 0x0CC7, + 0x0CC60CD6: 0x0CC8, + 0x0CC60CC2: 0x0CCA, + 0x0CCA0CD5: 0x0CCB, + 0x0D460D3E: 0x0D4A, + 0x0D470D3E: 0x0D4B, + 0x0D460D57: 0x0D4C, + 0x0DD90DCA: 0x0DDA, + 0x0DD90DCF: 0x0DDC, + 0x0DDC0DCA: 0x0DDD, + 0x0DD90DDF: 0x0DDE, + 0x1025102E: 0x1026, + 0x1B051B35: 0x1B06, + 0x1B071B35: 0x1B08, + 0x1B091B35: 0x1B0A, + 0x1B0B1B35: 0x1B0C, + 0x1B0D1B35: 0x1B0E, + 0x1B111B35: 0x1B12, + 0x1B3A1B35: 0x1B3B, + 0x1B3C1B35: 0x1B3D, + 0x1B3E1B35: 0x1B40, + 0x1B3F1B35: 0x1B41, + 0x1B421B35: 0x1B43, + 0x00410325: 0x1E00, + 0x00610325: 0x1E01, + 0x00420307: 0x1E02, + 0x00620307: 0x1E03, + 0x00420323: 0x1E04, + 0x00620323: 0x1E05, + 0x00420331: 0x1E06, + 0x00620331: 0x1E07, + 0x00C70301: 0x1E08, + 0x00E70301: 0x1E09, + 0x00440307: 0x1E0A, + 0x00640307: 0x1E0B, + 0x00440323: 0x1E0C, + 0x00640323: 0x1E0D, + 0x00440331: 0x1E0E, + 0x00640331: 0x1E0F, + 0x00440327: 0x1E10, + 0x00640327: 0x1E11, + 0x0044032D: 0x1E12, + 0x0064032D: 0x1E13, + 0x01120300: 0x1E14, + 0x01130300: 0x1E15, + 0x01120301: 0x1E16, + 0x01130301: 0x1E17, + 0x0045032D: 0x1E18, + 0x0065032D: 0x1E19, + 0x00450330: 0x1E1A, + 0x00650330: 0x1E1B, + 0x02280306: 0x1E1C, + 0x02290306: 0x1E1D, + 0x00460307: 0x1E1E, + 0x00660307: 0x1E1F, + 0x00470304: 0x1E20, + 0x00670304: 0x1E21, + 0x00480307: 0x1E22, + 0x00680307: 0x1E23, + 0x00480323: 0x1E24, + 0x00680323: 0x1E25, + 0x00480308: 0x1E26, + 0x00680308: 0x1E27, + 0x00480327: 0x1E28, + 0x00680327: 0x1E29, + 0x0048032E: 0x1E2A, + 0x0068032E: 0x1E2B, + 0x00490330: 0x1E2C, + 0x00690330: 0x1E2D, + 0x00CF0301: 0x1E2E, + 0x00EF0301: 0x1E2F, + 0x004B0301: 0x1E30, + 0x006B0301: 0x1E31, + 0x004B0323: 0x1E32, + 0x006B0323: 0x1E33, + 0x004B0331: 0x1E34, + 0x006B0331: 0x1E35, + 0x004C0323: 0x1E36, + 0x006C0323: 0x1E37, + 0x1E360304: 0x1E38, + 0x1E370304: 0x1E39, + 0x004C0331: 0x1E3A, + 0x006C0331: 0x1E3B, + 0x004C032D: 0x1E3C, + 0x006C032D: 0x1E3D, + 0x004D0301: 0x1E3E, + 0x006D0301: 0x1E3F, + 0x004D0307: 0x1E40, + 0x006D0307: 0x1E41, + 0x004D0323: 0x1E42, + 0x006D0323: 0x1E43, + 0x004E0307: 0x1E44, + 0x006E0307: 0x1E45, + 0x004E0323: 0x1E46, + 0x006E0323: 0x1E47, + 0x004E0331: 0x1E48, + 0x006E0331: 0x1E49, + 0x004E032D: 0x1E4A, + 0x006E032D: 0x1E4B, + 0x00D50301: 0x1E4C, + 0x00F50301: 0x1E4D, + 0x00D50308: 0x1E4E, + 0x00F50308: 0x1E4F, + 0x014C0300: 0x1E50, + 0x014D0300: 0x1E51, + 0x014C0301: 0x1E52, + 0x014D0301: 0x1E53, + 0x00500301: 0x1E54, + 0x00700301: 0x1E55, + 0x00500307: 0x1E56, + 0x00700307: 0x1E57, + 0x00520307: 0x1E58, + 0x00720307: 0x1E59, + 0x00520323: 0x1E5A, + 0x00720323: 0x1E5B, + 0x1E5A0304: 0x1E5C, + 0x1E5B0304: 0x1E5D, + 0x00520331: 0x1E5E, + 0x00720331: 0x1E5F, + 0x00530307: 0x1E60, + 0x00730307: 0x1E61, + 0x00530323: 0x1E62, + 0x00730323: 0x1E63, + 0x015A0307: 0x1E64, + 0x015B0307: 0x1E65, + 0x01600307: 0x1E66, + 0x01610307: 0x1E67, + 0x1E620307: 0x1E68, + 0x1E630307: 0x1E69, + 0x00540307: 0x1E6A, + 0x00740307: 0x1E6B, + 0x00540323: 0x1E6C, + 0x00740323: 0x1E6D, + 0x00540331: 0x1E6E, + 0x00740331: 0x1E6F, + 0x0054032D: 0x1E70, + 0x0074032D: 0x1E71, + 0x00550324: 0x1E72, + 0x00750324: 0x1E73, + 0x00550330: 0x1E74, + 0x00750330: 0x1E75, + 0x0055032D: 0x1E76, + 0x0075032D: 0x1E77, + 0x01680301: 0x1E78, + 0x01690301: 0x1E79, + 0x016A0308: 0x1E7A, + 0x016B0308: 0x1E7B, + 0x00560303: 0x1E7C, + 0x00760303: 0x1E7D, + 0x00560323: 0x1E7E, + 0x00760323: 0x1E7F, + 0x00570300: 0x1E80, + 0x00770300: 0x1E81, + 0x00570301: 0x1E82, + 0x00770301: 0x1E83, + 0x00570308: 0x1E84, + 0x00770308: 0x1E85, + 0x00570307: 0x1E86, + 0x00770307: 0x1E87, + 0x00570323: 0x1E88, + 0x00770323: 0x1E89, + 0x00580307: 0x1E8A, + 0x00780307: 0x1E8B, + 0x00580308: 0x1E8C, + 0x00780308: 0x1E8D, + 0x00590307: 0x1E8E, + 0x00790307: 0x1E8F, + 0x005A0302: 0x1E90, + 0x007A0302: 0x1E91, + 0x005A0323: 0x1E92, + 0x007A0323: 0x1E93, + 0x005A0331: 0x1E94, + 0x007A0331: 0x1E95, + 0x00680331: 0x1E96, + 0x00740308: 0x1E97, + 0x0077030A: 0x1E98, + 0x0079030A: 0x1E99, + 0x017F0307: 0x1E9B, + 0x00410323: 0x1EA0, + 0x00610323: 0x1EA1, + 0x00410309: 0x1EA2, + 0x00610309: 0x1EA3, + 0x00C20301: 0x1EA4, + 0x00E20301: 0x1EA5, + 0x00C20300: 0x1EA6, + 0x00E20300: 0x1EA7, + 0x00C20309: 0x1EA8, + 0x00E20309: 0x1EA9, + 0x00C20303: 0x1EAA, + 0x00E20303: 0x1EAB, + 0x1EA00302: 0x1EAC, + 0x1EA10302: 0x1EAD, + 0x01020301: 0x1EAE, + 0x01030301: 0x1EAF, + 0x01020300: 0x1EB0, + 0x01030300: 0x1EB1, + 0x01020309: 0x1EB2, + 0x01030309: 0x1EB3, + 0x01020303: 0x1EB4, + 0x01030303: 0x1EB5, + 0x1EA00306: 0x1EB6, + 0x1EA10306: 0x1EB7, + 0x00450323: 0x1EB8, + 0x00650323: 0x1EB9, + 0x00450309: 0x1EBA, + 0x00650309: 0x1EBB, + 0x00450303: 0x1EBC, + 0x00650303: 0x1EBD, + 0x00CA0301: 0x1EBE, + 0x00EA0301: 0x1EBF, + 0x00CA0300: 0x1EC0, + 0x00EA0300: 0x1EC1, + 0x00CA0309: 0x1EC2, + 0x00EA0309: 0x1EC3, + 0x00CA0303: 0x1EC4, + 0x00EA0303: 0x1EC5, + 0x1EB80302: 0x1EC6, + 0x1EB90302: 0x1EC7, + 0x00490309: 0x1EC8, + 0x00690309: 0x1EC9, + 0x00490323: 0x1ECA, + 0x00690323: 0x1ECB, + 0x004F0323: 0x1ECC, + 0x006F0323: 0x1ECD, + 0x004F0309: 0x1ECE, + 0x006F0309: 0x1ECF, + 0x00D40301: 0x1ED0, + 0x00F40301: 0x1ED1, + 0x00D40300: 0x1ED2, + 0x00F40300: 0x1ED3, + 0x00D40309: 0x1ED4, + 0x00F40309: 0x1ED5, + 0x00D40303: 0x1ED6, + 0x00F40303: 0x1ED7, + 0x1ECC0302: 0x1ED8, + 0x1ECD0302: 0x1ED9, + 0x01A00301: 0x1EDA, + 0x01A10301: 0x1EDB, + 0x01A00300: 0x1EDC, + 0x01A10300: 0x1EDD, + 0x01A00309: 0x1EDE, + 0x01A10309: 0x1EDF, + 0x01A00303: 0x1EE0, + 0x01A10303: 0x1EE1, + 0x01A00323: 0x1EE2, + 0x01A10323: 0x1EE3, + 0x00550323: 0x1EE4, + 0x00750323: 0x1EE5, + 0x00550309: 0x1EE6, + 0x00750309: 0x1EE7, + 0x01AF0301: 0x1EE8, + 0x01B00301: 0x1EE9, + 0x01AF0300: 0x1EEA, + 0x01B00300: 0x1EEB, + 0x01AF0309: 0x1EEC, + 0x01B00309: 0x1EED, + 0x01AF0303: 0x1EEE, + 0x01B00303: 0x1EEF, + 0x01AF0323: 0x1EF0, + 0x01B00323: 0x1EF1, + 0x00590300: 0x1EF2, + 0x00790300: 0x1EF3, + 0x00590323: 0x1EF4, + 0x00790323: 0x1EF5, + 0x00590309: 0x1EF6, + 0x00790309: 0x1EF7, + 0x00590303: 0x1EF8, + 0x00790303: 0x1EF9, + 0x03B10313: 0x1F00, + 0x03B10314: 0x1F01, + 0x1F000300: 0x1F02, + 0x1F010300: 0x1F03, + 0x1F000301: 0x1F04, + 0x1F010301: 0x1F05, + 0x1F000342: 0x1F06, + 0x1F010342: 0x1F07, + 0x03910313: 0x1F08, + 0x03910314: 0x1F09, + 0x1F080300: 0x1F0A, + 0x1F090300: 0x1F0B, + 0x1F080301: 0x1F0C, + 0x1F090301: 0x1F0D, + 0x1F080342: 0x1F0E, + 0x1F090342: 0x1F0F, + 0x03B50313: 0x1F10, + 0x03B50314: 0x1F11, + 0x1F100300: 0x1F12, + 0x1F110300: 0x1F13, + 0x1F100301: 0x1F14, + 0x1F110301: 0x1F15, + 0x03950313: 0x1F18, + 0x03950314: 0x1F19, + 0x1F180300: 0x1F1A, + 0x1F190300: 0x1F1B, + 0x1F180301: 0x1F1C, + 0x1F190301: 0x1F1D, + 0x03B70313: 0x1F20, + 0x03B70314: 0x1F21, + 0x1F200300: 0x1F22, + 0x1F210300: 0x1F23, + 0x1F200301: 0x1F24, + 0x1F210301: 0x1F25, + 0x1F200342: 0x1F26, + 0x1F210342: 0x1F27, + 0x03970313: 0x1F28, + 0x03970314: 0x1F29, + 0x1F280300: 0x1F2A, + 0x1F290300: 0x1F2B, + 0x1F280301: 0x1F2C, + 0x1F290301: 0x1F2D, + 0x1F280342: 0x1F2E, + 0x1F290342: 0x1F2F, + 0x03B90313: 0x1F30, + 0x03B90314: 0x1F31, + 0x1F300300: 0x1F32, + 0x1F310300: 0x1F33, + 0x1F300301: 0x1F34, + 0x1F310301: 0x1F35, + 0x1F300342: 0x1F36, + 0x1F310342: 0x1F37, + 0x03990313: 0x1F38, + 0x03990314: 0x1F39, + 0x1F380300: 0x1F3A, + 0x1F390300: 0x1F3B, + 0x1F380301: 0x1F3C, + 0x1F390301: 0x1F3D, + 0x1F380342: 0x1F3E, + 0x1F390342: 0x1F3F, + 0x03BF0313: 0x1F40, + 0x03BF0314: 0x1F41, + 0x1F400300: 0x1F42, + 0x1F410300: 0x1F43, + 0x1F400301: 0x1F44, + 0x1F410301: 0x1F45, + 0x039F0313: 0x1F48, + 0x039F0314: 0x1F49, + 0x1F480300: 0x1F4A, + 0x1F490300: 0x1F4B, + 0x1F480301: 0x1F4C, + 0x1F490301: 0x1F4D, + 0x03C50313: 0x1F50, + 0x03C50314: 0x1F51, + 0x1F500300: 0x1F52, + 0x1F510300: 0x1F53, + 0x1F500301: 0x1F54, + 0x1F510301: 0x1F55, + 0x1F500342: 0x1F56, + 0x1F510342: 0x1F57, + 0x03A50314: 0x1F59, + 0x1F590300: 0x1F5B, + 0x1F590301: 0x1F5D, + 0x1F590342: 0x1F5F, + 0x03C90313: 0x1F60, + 0x03C90314: 0x1F61, + 0x1F600300: 0x1F62, + 0x1F610300: 0x1F63, + 0x1F600301: 0x1F64, + 0x1F610301: 0x1F65, + 0x1F600342: 0x1F66, + 0x1F610342: 0x1F67, + 0x03A90313: 0x1F68, + 0x03A90314: 0x1F69, + 0x1F680300: 0x1F6A, + 0x1F690300: 0x1F6B, + 0x1F680301: 0x1F6C, + 0x1F690301: 0x1F6D, + 0x1F680342: 0x1F6E, + 0x1F690342: 0x1F6F, + 0x03B10300: 0x1F70, + 0x03B50300: 0x1F72, + 0x03B70300: 0x1F74, + 0x03B90300: 0x1F76, + 0x03BF0300: 0x1F78, + 0x03C50300: 0x1F7A, + 0x03C90300: 0x1F7C, + 0x1F000345: 0x1F80, + 0x1F010345: 0x1F81, + 0x1F020345: 0x1F82, + 0x1F030345: 0x1F83, + 0x1F040345: 0x1F84, + 0x1F050345: 0x1F85, + 0x1F060345: 0x1F86, + 0x1F070345: 0x1F87, + 0x1F080345: 0x1F88, + 0x1F090345: 0x1F89, + 0x1F0A0345: 0x1F8A, + 0x1F0B0345: 0x1F8B, + 0x1F0C0345: 0x1F8C, + 0x1F0D0345: 0x1F8D, + 0x1F0E0345: 0x1F8E, + 0x1F0F0345: 0x1F8F, + 0x1F200345: 0x1F90, + 0x1F210345: 0x1F91, + 0x1F220345: 0x1F92, + 0x1F230345: 0x1F93, + 0x1F240345: 0x1F94, + 0x1F250345: 0x1F95, + 0x1F260345: 0x1F96, + 0x1F270345: 0x1F97, + 0x1F280345: 0x1F98, + 0x1F290345: 0x1F99, + 0x1F2A0345: 0x1F9A, + 0x1F2B0345: 0x1F9B, + 0x1F2C0345: 0x1F9C, + 0x1F2D0345: 0x1F9D, + 0x1F2E0345: 0x1F9E, + 0x1F2F0345: 0x1F9F, + 0x1F600345: 0x1FA0, + 0x1F610345: 0x1FA1, + 0x1F620345: 0x1FA2, + 0x1F630345: 0x1FA3, + 0x1F640345: 0x1FA4, + 0x1F650345: 0x1FA5, + 0x1F660345: 0x1FA6, + 0x1F670345: 0x1FA7, + 0x1F680345: 0x1FA8, + 0x1F690345: 0x1FA9, + 0x1F6A0345: 0x1FAA, + 0x1F6B0345: 0x1FAB, + 0x1F6C0345: 0x1FAC, + 0x1F6D0345: 0x1FAD, + 0x1F6E0345: 0x1FAE, + 0x1F6F0345: 0x1FAF, + 0x03B10306: 0x1FB0, + 0x03B10304: 0x1FB1, + 0x1F700345: 0x1FB2, + 0x03B10345: 0x1FB3, + 0x03AC0345: 0x1FB4, + 0x03B10342: 0x1FB6, + 0x1FB60345: 0x1FB7, + 0x03910306: 0x1FB8, + 0x03910304: 0x1FB9, + 0x03910300: 0x1FBA, + 0x03910345: 0x1FBC, + 0x00A80342: 0x1FC1, + 0x1F740345: 0x1FC2, + 0x03B70345: 0x1FC3, + 0x03AE0345: 0x1FC4, + 0x03B70342: 0x1FC6, + 0x1FC60345: 0x1FC7, + 0x03950300: 0x1FC8, + 0x03970300: 0x1FCA, + 0x03970345: 0x1FCC, + 0x1FBF0300: 0x1FCD, + 0x1FBF0301: 0x1FCE, + 0x1FBF0342: 0x1FCF, + 0x03B90306: 0x1FD0, + 0x03B90304: 0x1FD1, + 0x03CA0300: 0x1FD2, + 0x03B90342: 0x1FD6, + 0x03CA0342: 0x1FD7, + 0x03990306: 0x1FD8, + 0x03990304: 0x1FD9, + 0x03990300: 0x1FDA, + 0x1FFE0300: 0x1FDD, + 0x1FFE0301: 0x1FDE, + 0x1FFE0342: 0x1FDF, + 0x03C50306: 0x1FE0, + 0x03C50304: 0x1FE1, + 0x03CB0300: 0x1FE2, + 0x03C10313: 0x1FE4, + 0x03C10314: 0x1FE5, + 0x03C50342: 0x1FE6, + 0x03CB0342: 0x1FE7, + 0x03A50306: 0x1FE8, + 0x03A50304: 0x1FE9, + 0x03A50300: 0x1FEA, + 0x03A10314: 0x1FEC, + 0x00A80300: 0x1FED, + 0x1F7C0345: 0x1FF2, + 0x03C90345: 0x1FF3, + 0x03CE0345: 0x1FF4, + 0x03C90342: 0x1FF6, + 0x1FF60345: 0x1FF7, + 0x039F0300: 0x1FF8, + 0x03A90300: 0x1FFA, + 0x03A90345: 0x1FFC, + 0x21900338: 0x219A, + 0x21920338: 0x219B, + 0x21940338: 0x21AE, + 0x21D00338: 0x21CD, + 0x21D40338: 0x21CE, + 0x21D20338: 0x21CF, + 0x22030338: 0x2204, + 0x22080338: 0x2209, + 0x220B0338: 0x220C, + 0x22230338: 0x2224, + 0x22250338: 0x2226, + 0x223C0338: 0x2241, + 0x22430338: 0x2244, + 0x22450338: 0x2247, + 0x22480338: 0x2249, + 0x003D0338: 0x2260, + 0x22610338: 0x2262, + 0x224D0338: 0x226D, + 0x003C0338: 0x226E, + 0x003E0338: 0x226F, + 0x22640338: 0x2270, + 0x22650338: 0x2271, + 0x22720338: 0x2274, + 0x22730338: 0x2275, + 0x22760338: 0x2278, + 0x22770338: 0x2279, + 0x227A0338: 0x2280, + 0x227B0338: 0x2281, + 0x22820338: 0x2284, + 0x22830338: 0x2285, + 0x22860338: 0x2288, + 0x22870338: 0x2289, + 0x22A20338: 0x22AC, + 0x22A80338: 0x22AD, + 0x22A90338: 0x22AE, + 0x22AB0338: 0x22AF, + 0x227C0338: 0x22E0, + 0x227D0338: 0x22E1, + 0x22910338: 0x22E2, + 0x22920338: 0x22E3, + 0x22B20338: 0x22EA, + 0x22B30338: 0x22EB, + 0x22B40338: 0x22EC, + 0x22B50338: 0x22ED, + 0x304B3099: 0x304C, + 0x304D3099: 0x304E, + 0x304F3099: 0x3050, + 0x30513099: 0x3052, + 0x30533099: 0x3054, + 0x30553099: 0x3056, + 0x30573099: 0x3058, + 0x30593099: 0x305A, + 0x305B3099: 0x305C, + 0x305D3099: 0x305E, + 0x305F3099: 0x3060, + 0x30613099: 0x3062, + 0x30643099: 0x3065, + 0x30663099: 0x3067, + 0x30683099: 0x3069, + 0x306F3099: 0x3070, + 0x306F309A: 0x3071, + 0x30723099: 0x3073, + 0x3072309A: 0x3074, + 0x30753099: 0x3076, + 0x3075309A: 0x3077, + 0x30783099: 0x3079, + 0x3078309A: 0x307A, + 0x307B3099: 0x307C, + 0x307B309A: 0x307D, + 0x30463099: 0x3094, + 0x309D3099: 0x309E, + 0x30AB3099: 0x30AC, + 0x30AD3099: 0x30AE, + 0x30AF3099: 0x30B0, + 0x30B13099: 0x30B2, + 0x30B33099: 0x30B4, + 0x30B53099: 0x30B6, + 0x30B73099: 0x30B8, + 0x30B93099: 0x30BA, + 0x30BB3099: 0x30BC, + 0x30BD3099: 0x30BE, + 0x30BF3099: 0x30C0, + 0x30C13099: 0x30C2, + 0x30C43099: 0x30C5, + 0x30C63099: 0x30C7, + 0x30C83099: 0x30C9, + 0x30CF3099: 0x30D0, + 0x30CF309A: 0x30D1, + 0x30D23099: 0x30D3, + 0x30D2309A: 0x30D4, + 0x30D53099: 0x30D6, + 0x30D5309A: 0x30D7, + 0x30D83099: 0x30D9, + 0x30D8309A: 0x30DA, + 0x30DB3099: 0x30DC, + 0x30DB309A: 0x30DD, + 0x30A63099: 0x30F4, + 0x30EF3099: 0x30F7, + 0x30F03099: 0x30F8, + 0x30F13099: 0x30F9, + 0x30F23099: 0x30FA, + 0x30FD3099: 0x30FE, + 0x109910BA: 0x1109A, + 0x109B10BA: 0x1109C, + 0x10A510BA: 0x110AB, + 0x11311127: 0x1112E, + 0x11321127: 0x1112F, +} + +// Total size of tables: 51KB (52487 bytes) diff --git a/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/transform.go b/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/transform.go new file mode 100644 index 000000000..a36a60641 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/transform.go @@ -0,0 +1,85 @@ +// 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 norm + +import ( + "unicode/utf8" + + "code.google.com/p/go.text/transform" +) + +// Transform implements the transform.Transformer interface. It may need to +// write segments of up to MaxSegmentSize at once. Users should either catch +// ErrShortDst and allow dst to grow or have dst be at least of size +// MaxTransformChunkSize to be guaranteed of progress. +func (f Form) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) { + n := 0 + // Cap the maximum number of src bytes to check. + b := src + eof := atEOF + if ns := len(dst); ns < len(b) { + err = transform.ErrShortDst + eof = false + b = b[:ns] + } + i, ok := formTable[f].quickSpan(inputBytes(b), n, len(b), eof) + n += copy(dst[n:], b[n:i]) + if !ok { + nDst, nSrc, err = f.transform(dst[n:], src[n:], atEOF) + return nDst + n, nSrc + n, err + } + if n < len(src) && !atEOF { + err = transform.ErrShortSrc + } + return n, n, err +} + +func flushTransform(rb *reorderBuffer) bool { + // Write out (must fully fit in dst, or else it is a ErrShortDst). + if len(rb.out) < rb.nrune*utf8.UTFMax { + return false + } + rb.out = rb.out[rb.flushCopy(rb.out):] + return true +} + +var errs = []error{nil, transform.ErrShortDst, transform.ErrShortSrc} + +// transform implements the transform.Transformer interface. It is only called +// when quickSpan does not pass for a given string. +func (f Form) transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) { + // TODO: get rid of reorderBuffer. See CL 23460044. + rb := reorderBuffer{} + rb.init(f, src) + for { + // Load segment into reorder buffer. + rb.setFlusher(dst[nDst:], flushTransform) + end := decomposeSegment(&rb, nSrc, atEOF) + if end < 0 { + return nDst, nSrc, errs[-end] + } + nDst = len(dst) - len(rb.out) + nSrc = end + + // Next quickSpan. + end = rb.nsrc + eof := atEOF + if n := nSrc + len(dst) - nDst; n < end { + err = transform.ErrShortDst + end = n + eof = false + } + end, ok := rb.f.quickSpan(rb.src, nSrc, end, eof) + n := copy(dst[nDst:], rb.src.bytes[nSrc:end]) + nSrc += n + nDst += n + if ok { + if n < rb.nsrc && !atEOF { + err = transform.ErrShortSrc + } + return nDst, nSrc, err + } + } +} diff --git a/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/transform_test.go b/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/transform_test.go new file mode 100644 index 000000000..12b95ee4c --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/transform_test.go @@ -0,0 +1,101 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package norm + +import ( + "fmt" + "testing" + + "code.google.com/p/go.text/transform" +) + +func TestTransform(t *testing.T) { + tests := []struct { + f Form + in, out string + eof bool + dstSize int + err error + }{ + {NFC, "ab", "ab", true, 2, nil}, + {NFC, "qx", "qx", true, 2, nil}, + {NFD, "qx", "qx", true, 2, nil}, + {NFC, "", "", true, 1, nil}, + {NFD, "", "", true, 1, nil}, + {NFC, "", "", false, 1, nil}, + {NFD, "", "", false, 1, nil}, + + // Normalized segment does not fit in destination. + {NFD, "ö", "", true, 1, transform.ErrShortDst}, + {NFD, "ö", "", true, 2, transform.ErrShortDst}, + + // As an artifact of the algorithm, only full segments are written. + // This is not strictly required, and some bytes could be written. + // In practice, for Transform to not block, the destination buffer + // should be at least MaxSegmentSize to work anyway and these edge + // conditions will be relatively rare. + {NFC, "ab", "", true, 1, transform.ErrShortDst}, + // This is even true for inert runes. + {NFC, "qx", "", true, 1, transform.ErrShortDst}, + {NFC, "a\u0300abc", "\u00e0a", true, 4, transform.ErrShortDst}, + + // We cannot write a segment if succesive runes could still change the result. + {NFD, "ö", "", false, 3, transform.ErrShortSrc}, + {NFC, "a\u0300", "", false, 4, transform.ErrShortSrc}, + {NFD, "a\u0300", "", false, 4, transform.ErrShortSrc}, + {NFC, "ö", "", false, 3, transform.ErrShortSrc}, + + {NFC, "a\u0300", "", true, 1, transform.ErrShortDst}, + // Theoretically could fit, but won't due to simplified checks. + {NFC, "a\u0300", "", true, 2, transform.ErrShortDst}, + {NFC, "a\u0300", "", true, 3, transform.ErrShortDst}, + {NFC, "a\u0300", "\u00e0", true, 4, nil}, + + {NFD, "öa\u0300", "o\u0308", false, 8, transform.ErrShortSrc}, + {NFD, "öa\u0300ö", "o\u0308a\u0300", true, 8, transform.ErrShortDst}, + {NFD, "öa\u0300ö", "o\u0308a\u0300", false, 12, transform.ErrShortSrc}, + + // Illegal input is copied verbatim. + {NFD, "\xbd\xb2=\xbc ", "\xbd\xb2=\xbc ", true, 8, nil}, + } + b := make([]byte, 100) + for i, tt := range tests { + nDst, _, err := tt.f.Transform(b[:tt.dstSize], []byte(tt.in), tt.eof) + out := string(b[:nDst]) + if out != tt.out || err != tt.err { + t.Errorf("%d: was %+q (%v); want %+q (%v)", i, out, err, tt.out, tt.err) + } + if want := tt.f.String(tt.in)[:nDst]; want != out { + t.Errorf("%d: incorect normalization: was %+q; want %+q", i, out, want) + } + } +} + +var transBufSizes = []int{ + MaxTransformChunkSize, + 3 * MaxTransformChunkSize / 2, + 2 * MaxTransformChunkSize, + 3 * MaxTransformChunkSize, + 100 * MaxTransformChunkSize, +} + +func doTransNorm(f Form, buf []byte, b []byte) []byte { + acc := []byte{} + for p := 0; p < len(b); { + nd, ns, _ := f.Transform(buf[:], b[p:], true) + p += ns + acc = append(acc, buf[:nd]...) + } + return acc +} + +func TestTransformNorm(t *testing.T) { + for _, sz := range transBufSizes { + buf := make([]byte, sz) + runNormTests(t, fmt.Sprintf("Transform:%d", sz), func(f Form, out []byte, s string) []byte { + return doTransNorm(f, buf, append(out, s...)) + }) + } +} diff --git a/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/trie.go b/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/trie.go new file mode 100644 index 000000000..82267a8d3 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/trie.go @@ -0,0 +1,232 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package norm + +type valueRange struct { + value uint16 // header: value:stride + lo, hi byte // header: lo:n +} + +type trie struct { + index []uint8 + values []uint16 + sparse []valueRange + sparseOffset []uint16 + cutoff uint8 // indices >= cutoff are sparse +} + +// lookupValue determines the type of block n and looks up the value for b. +// For n < t.cutoff, the block is a simple lookup table. Otherwise, the block +// is a list of ranges with an accompanying value. Given a matching range r, +// the value for b is by r.value + (b - r.lo) * stride. +func (t *trie) lookupValue(n uint8, b byte) uint16 { + if n < t.cutoff { + return t.values[uint16(n)<<6+uint16(b)] + } + offset := t.sparseOffset[n-t.cutoff] + header := t.sparse[offset] + lo := offset + 1 + hi := lo + uint16(header.lo) + for lo < hi { + m := lo + (hi-lo)/2 + r := t.sparse[m] + if r.lo <= b && b <= r.hi { + return r.value + uint16(b-r.lo)*header.value + } + if b < r.lo { + hi = m + } else { + lo = m + 1 + } + } + return 0 +} + +const ( + t1 = 0x00 // 0000 0000 + tx = 0x80 // 1000 0000 + t2 = 0xC0 // 1100 0000 + t3 = 0xE0 // 1110 0000 + t4 = 0xF0 // 1111 0000 + t5 = 0xF8 // 1111 1000 + t6 = 0xFC // 1111 1100 + te = 0xFE // 1111 1110 +) + +// 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 *trie) lookup(s []byte) (v uint16, sz int) { + c0 := s[0] + switch { + case c0 < tx: + return t.values[c0], 1 + case c0 < t2: + return 0, 1 + case c0 < t3: + if len(s) < 2 { + return 0, 0 + } + i := t.index[c0] + c1 := s[1] + if c1 < tx || t2 <= c1 { + return 0, 1 + } + return t.lookupValue(i, c1), 2 + case c0 < t4: + if len(s) < 3 { + return 0, 0 + } + i := t.index[c0] + c1 := s[1] + if c1 < tx || t2 <= c1 { + return 0, 1 + } + o := uint16(i)<<6 + uint16(c1) + i = t.index[o] + c2 := s[2] + if c2 < tx || t2 <= c2 { + return 0, 2 + } + return t.lookupValue(i, c2), 3 + case c0 < t5: + if len(s) < 4 { + return 0, 0 + } + i := t.index[c0] + c1 := s[1] + if c1 < tx || t2 <= c1 { + return 0, 1 + } + o := uint16(i)<<6 + uint16(c1) + i = t.index[o] + c2 := s[2] + if c2 < tx || t2 <= c2 { + return 0, 2 + } + o = uint16(i)<<6 + uint16(c2) + i = t.index[o] + c3 := s[3] + if c3 < tx || t2 <= c3 { + return 0, 3 + } + return t.lookupValue(i, c3), 4 + } + // Illegal rune + return 0, 1 +} + +// 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 *trie) lookupString(s string) (v uint16, sz int) { + c0 := s[0] + switch { + case c0 < tx: + return t.values[c0], 1 + case c0 < t2: + return 0, 1 + case c0 < t3: + if len(s) < 2 { + return 0, 0 + } + i := t.index[c0] + c1 := s[1] + if c1 < tx || t2 <= c1 { + return 0, 1 + } + return t.lookupValue(i, c1), 2 + case c0 < t4: + if len(s) < 3 { + return 0, 0 + } + i := t.index[c0] + c1 := s[1] + if c1 < tx || t2 <= c1 { + return 0, 1 + } + o := uint16(i)<<6 + uint16(c1) + i = t.index[o] + c2 := s[2] + if c2 < tx || t2 <= c2 { + return 0, 2 + } + return t.lookupValue(i, c2), 3 + case c0 < t5: + if len(s) < 4 { + return 0, 0 + } + i := t.index[c0] + c1 := s[1] + if c1 < tx || t2 <= c1 { + return 0, 1 + } + o := uint16(i)<<6 + uint16(c1) + i = t.index[o] + c2 := s[2] + if c2 < tx || t2 <= c2 { + return 0, 2 + } + o = uint16(i)<<6 + uint16(c2) + i = t.index[o] + c3 := s[3] + if c3 < tx || t2 <= c3 { + return 0, 3 + } + return t.lookupValue(i, c3), 4 + } + // Illegal rune + return 0, 1 +} + +// lookupUnsafe returns the trie value for the first UTF-8 encoding in s. +// s must hold a full encoding. +func (t *trie) lookupUnsafe(s []byte) uint16 { + c0 := s[0] + if c0 < tx { + return t.values[c0] + } + if c0 < t2 { + return 0 + } + i := t.index[c0] + if c0 < t3 { + return t.lookupValue(i, s[1]) + } + i = t.index[uint16(i)<<6+uint16(s[1])] + if c0 < t4 { + return t.lookupValue(i, s[2]) + } + i = t.index[uint16(i)<<6+uint16(s[2])] + if c0 < t5 { + return t.lookupValue(i, s[3]) + } + return 0 +} + +// lookupStringUnsafe returns the trie value for the first UTF-8 encoding in s. +// s must hold a full encoding. +func (t *trie) lookupStringUnsafe(s string) uint16 { + c0 := s[0] + if c0 < tx { + return t.values[c0] + } + if c0 < t2 { + return 0 + } + i := t.index[c0] + if c0 < t3 { + return t.lookupValue(i, s[1]) + } + i = t.index[uint16(i)<<6+uint16(s[1])] + if c0 < t4 { + return t.lookupValue(i, s[2]) + } + i = t.index[uint16(i)<<6+uint16(s[2])] + if c0 < t5 { + return t.lookupValue(i, s[3]) + } + return 0 +} diff --git a/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/trie_test.go b/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/trie_test.go new file mode 100644 index 000000000..1a75cc705 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/trie_test.go @@ -0,0 +1,152 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package norm + +import ( + "testing" + "unicode/utf8" +) + +// Test data is located in triedata_test.go; generated by maketesttables. +var testdata = testdataTrie + +type rangeTest struct { + block uint8 + lookup byte + result uint16 + table []valueRange + offsets []uint16 +} + +var range1Off = []uint16{0, 2} +var range1 = []valueRange{ + {0, 1, 0}, + {1, 0x80, 0x80}, + {0, 2, 0}, + {1, 0x80, 0x80}, + {9, 0xff, 0xff}, +} + +var rangeTests = []rangeTest{ + {10, 0x80, 1, range1, range1Off}, + {10, 0x00, 0, range1, range1Off}, + {11, 0x80, 1, range1, range1Off}, + {11, 0xff, 9, range1, range1Off}, + {11, 0x00, 0, range1, range1Off}, +} + +func TestLookupSparse(t *testing.T) { + for i, test := range rangeTests { + n := trie{sparse: test.table, sparseOffset: test.offsets, cutoff: 10} + v := n.lookupValue(test.block, test.lookup) + if v != test.result { + t.Errorf("LookupSparse:%d: found %X; want %X", i, v, test.result) + } + } +} + +// Test cases for illegal runes. +type trietest struct { + size int + bytes []byte +} + +var tests = []trietest{ + // illegal runes + {1, []byte{0x80}}, + {1, []byte{0xFF}}, + {1, []byte{t2, tx - 1}}, + {1, []byte{t2, t2}}, + {2, []byte{t3, tx, tx - 1}}, + {2, []byte{t3, tx, t2}}, + {1, []byte{t3, tx - 1, tx}}, + {3, []byte{t4, tx, tx, tx - 1}}, + {3, []byte{t4, tx, tx, t2}}, + {1, []byte{t4, t2, tx, tx - 1}}, + {2, []byte{t4, tx, t2, tx - 1}}, + + // short runes + {0, []byte{t2}}, + {0, []byte{t3, tx}}, + {0, []byte{t4, tx, tx}}, + + // we only support UTF-8 up to utf8.UTFMax bytes (4 bytes) + {1, []byte{t5, tx, tx, tx, tx}}, + {1, []byte{t6, tx, tx, tx, tx, tx}}, +} + +func mkUTF8(r rune) ([]byte, int) { + var b [utf8.UTFMax]byte + sz := utf8.EncodeRune(b[:], r) + return b[:sz], sz +} + +func TestLookup(t *testing.T) { + for i, tt := range testRunes { + b, szg := mkUTF8(tt) + v, szt := testdata.lookup(b) + if int(v) != i { + t.Errorf("lookup(%U): found value %#x, expected %#x", tt, v, i) + } + if szt != szg { + t.Errorf("lookup(%U): found size %d, expected %d", tt, szt, szg) + } + } + for i, tt := range tests { + v, sz := testdata.lookup(tt.bytes) + if v != 0 { + t.Errorf("lookup of illegal rune, case %d: found value %#x, expected 0", i, v) + } + if sz != tt.size { + t.Errorf("lookup of illegal rune, case %d: found size %d, expected %d", i, sz, tt.size) + } + } + // Verify defaults. + if v, _ := testdata.lookup([]byte{0xC1, 0x8C}); v != 0 { + t.Errorf("lookup of non-existing rune should be 0; found %X", v) + } +} + +func TestLookupUnsafe(t *testing.T) { + for i, tt := range testRunes { + b, _ := mkUTF8(tt) + v := testdata.lookupUnsafe(b) + if int(v) != i { + t.Errorf("lookupUnsafe(%U): found value %#x, expected %#x", i, v, i) + } + } +} + +func TestLookupString(t *testing.T) { + for i, tt := range testRunes { + b, szg := mkUTF8(tt) + v, szt := testdata.lookupString(string(b)) + if int(v) != i { + t.Errorf("lookup(%U): found value %#x, expected %#x", i, v, i) + } + if szt != szg { + t.Errorf("lookup(%U): found size %d, expected %d", i, szt, szg) + } + } + for i, tt := range tests { + v, sz := testdata.lookupString(string(tt.bytes)) + if int(v) != 0 { + t.Errorf("lookup of illegal rune, case %d: found value %#x, expected 0", i, v) + } + if sz != tt.size { + t.Errorf("lookup of illegal rune, case %d: found size %d, expected %d", i, sz, tt.size) + } + } +} + +func TestLookupStringUnsafe(t *testing.T) { + for i, tt := range testRunes { + b, _ := mkUTF8(tt) + v := testdata.lookupStringUnsafe(string(b)) + if int(v) != i { + t.Errorf("lookupUnsafe(%U): found value %#x, expected %#x", i, v, i) + } + } +} diff --git a/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/triedata_test.go b/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/triedata_test.go new file mode 100644 index 000000000..d6c832d46 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/triedata_test.go @@ -0,0 +1,85 @@ +// Generated by running +// maketesttables +// DO NOT EDIT + +package norm + +var testRunes = []int32{1, 12, 127, 128, 256, 2047, 2048, 2457, 65535, 65536, 65793, 1114111, 512, 513, 514, 528, 533} + +// testdataValues: 192 entries, 384 bytes +// Block 2 is the null block. +var testdataValues = [192]uint16{ + // Block 0x0, offset 0x0 + 0x000c: 0x0001, + // Block 0x1, offset 0x40 + 0x007f: 0x0002, + // Block 0x2, offset 0x80 +} + +// testdataSparseOffset: 10 entries, 20 bytes +var testdataSparseOffset = []uint16{0x0, 0x2, 0x4, 0x8, 0xa, 0xc, 0xe, 0x10, 0x12, 0x14} + +// testdataSparseValues: 22 entries, 88 bytes +var testdataSparseValues = [22]valueRange{ + // Block 0x0, offset 0x1 + {value: 0x0000, lo: 0x01}, + {value: 0x0003, lo: 0x80, hi: 0x80}, + // Block 0x1, offset 0x2 + {value: 0x0000, lo: 0x01}, + {value: 0x0004, lo: 0x80, hi: 0x80}, + // Block 0x2, offset 0x3 + {value: 0x0001, lo: 0x03}, + {value: 0x000c, lo: 0x80, hi: 0x82}, + {value: 0x000f, lo: 0x90, hi: 0x90}, + {value: 0x0010, lo: 0x95, hi: 0x95}, + // Block 0x3, offset 0x4 + {value: 0x0000, lo: 0x01}, + {value: 0x0005, lo: 0xbf, hi: 0xbf}, + // Block 0x4, offset 0x5 + {value: 0x0000, lo: 0x01}, + {value: 0x0006, lo: 0x80, hi: 0x80}, + // Block 0x5, offset 0x6 + {value: 0x0000, lo: 0x01}, + {value: 0x0007, lo: 0x99, hi: 0x99}, + // Block 0x6, offset 0x7 + {value: 0x0000, lo: 0x01}, + {value: 0x0008, lo: 0xbf, hi: 0xbf}, + // Block 0x7, offset 0x8 + {value: 0x0000, lo: 0x01}, + {value: 0x0009, lo: 0x80, hi: 0x80}, + // Block 0x8, offset 0x9 + {value: 0x0000, lo: 0x01}, + {value: 0x000a, lo: 0x81, hi: 0x81}, + // Block 0x9, offset 0xa + {value: 0x0000, lo: 0x01}, + {value: 0x000b, lo: 0xbf, hi: 0xbf}, +} + +// testdataLookup: 640 bytes +// Block 0 is the null block. +var testdataLookup = [640]uint8{ + // Block 0x0, offset 0x0 + // Block 0x1, offset 0x40 + // Block 0x2, offset 0x80 + // Block 0x3, offset 0xc0 + 0x0c2: 0x01, 0x0c4: 0x02, + 0x0c8: 0x03, + 0x0df: 0x04, + 0x0e0: 0x02, + 0x0ef: 0x03, + 0x0f0: 0x05, 0x0f4: 0x07, + // Block 0x4, offset 0x100 + 0x120: 0x05, 0x126: 0x06, + // Block 0x5, offset 0x140 + 0x17f: 0x07, + // Block 0x6, offset 0x180 + 0x180: 0x08, 0x184: 0x09, + // Block 0x7, offset 0x1c0 + 0x1d0: 0x04, + // Block 0x8, offset 0x200 + 0x23f: 0x0a, + // Block 0x9, offset 0x240 + 0x24f: 0x06, +} + +var testdataTrie = trie{testdataLookup[:], testdataValues[:], testdataSparseValues[:], testdataSparseOffset[:], 1} diff --git a/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/triegen.go b/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/triegen.go new file mode 100644 index 000000000..52c88b039 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/triegen.go @@ -0,0 +1,317 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build ignore + +// Trie table generator. +// Used by make*tables tools to generate a go file with trie data structures +// for mapping UTF-8 to a 16-bit value. All but the last byte in a UTF-8 byte +// sequence are used to lookup offsets in the index table to be used for the +// next byte. The last byte is used to index into a table with 16-bit values. + +package main + +import ( + "fmt" + "hash/crc32" + "log" + "unicode/utf8" +) + +const ( + blockSize = 64 + blockOffset = 2 // Subtract two blocks to compensate for the 0x80 added to continuation bytes. + maxSparseEntries = 16 +) + +// Intermediate trie structure +type trieNode struct { + table [256]*trieNode + value int + b byte + leaf bool +} + +func newNode() *trieNode { + return new(trieNode) +} + +func (n trieNode) String() string { + s := fmt.Sprint("trieNode{table: { non-nil at index: ") + for i, v := range n.table { + if v != nil { + s += fmt.Sprintf("%d, ", i) + } + } + s += fmt.Sprintf("}, value:%#x, b:%#x leaf:%v}", n.value, n.b, n.leaf) + return s +} + +func (n trieNode) isInternal() bool { + internal := true + for i := 0; i < 256; i++ { + if nn := n.table[i]; nn != nil { + if !internal && !nn.leaf { + log.Fatalf("triegen: isInternal: node contains both leaf and non-leaf children (%v)", n) + } + internal = internal && !nn.leaf + } + } + return internal +} + +func (n trieNode) mostFrequentStride() int { + counts := make(map[int]int) + v := 0 + for _, t := range n.table[0x80 : 0x80+blockSize] { + if t != nil { + if stride := t.value - v; v != 0 && stride >= 0 { + counts[stride]++ + } + v = t.value + } else { + v = 0 + } + } + var maxs, maxc int + for stride, cnt := range counts { + if cnt > maxc || (cnt == maxc && stride < maxs) { + maxs, maxc = stride, cnt + } + } + return maxs +} + +func (n trieNode) countSparseEntries() int { + stride := n.mostFrequentStride() + var count, v int + for _, t := range n.table[0x80 : 0x80+blockSize] { + tv := 0 + if t != nil { + tv = t.value + } + if tv-v != stride { + if tv != 0 { + count++ + } + } + v = tv + } + return count +} + +func (n *trieNode) insert(r rune, value uint16) { + var p [utf8.UTFMax]byte + sz := utf8.EncodeRune(p[:], r) + + for i := 0; i < sz; i++ { + if n.leaf { + log.Fatalf("triegen: insert: node (%#v) should not be a leaf", n) + } + nn := n.table[p[i]] + if nn == nil { + nn = newNode() + nn.b = p[i] + n.table[p[i]] = nn + } + n = nn + } + n.value = int(value) + n.leaf = true +} + +type nodeIndex struct { + lookupBlocks []*trieNode + valueBlocks []*trieNode + sparseBlocks []*trieNode + sparseOffset []uint16 + sparseCount int + + lookupBlockIdx map[uint32]int + valueBlockIdx map[uint32]int +} + +func newIndex() *nodeIndex { + index := &nodeIndex{} + index.lookupBlocks = make([]*trieNode, 0) + index.valueBlocks = make([]*trieNode, 0) + index.sparseBlocks = make([]*trieNode, 0) + index.sparseOffset = make([]uint16, 1) + index.lookupBlockIdx = make(map[uint32]int) + index.valueBlockIdx = make(map[uint32]int) + return index +} + +func computeOffsets(index *nodeIndex, n *trieNode) int { + if n.leaf { + return n.value + } + hasher := crc32.New(crc32.MakeTable(crc32.IEEE)) + // We only index continuation bytes. + for i := 0; i < blockSize; i++ { + v := 0 + if nn := n.table[0x80+i]; nn != nil { + v = computeOffsets(index, nn) + } + hasher.Write([]byte{uint8(v >> 8), uint8(v)}) + } + h := hasher.Sum32() + if n.isInternal() { + v, ok := index.lookupBlockIdx[h] + if !ok { + v = len(index.lookupBlocks) - blockOffset + index.lookupBlocks = append(index.lookupBlocks, n) + index.lookupBlockIdx[h] = v + } + n.value = v + } else { + v, ok := index.valueBlockIdx[h] + if !ok { + if c := n.countSparseEntries(); c > maxSparseEntries { + v = len(index.valueBlocks) - blockOffset + index.valueBlocks = append(index.valueBlocks, n) + index.valueBlockIdx[h] = v + } else { + v = -len(index.sparseOffset) + index.sparseBlocks = append(index.sparseBlocks, n) + index.sparseOffset = append(index.sparseOffset, uint16(index.sparseCount)) + index.sparseCount += c + 1 + index.valueBlockIdx[h] = v + } + } + n.value = v + } + return n.value +} + +func printValueBlock(nr int, n *trieNode, offset int) { + boff := nr * blockSize + fmt.Printf("\n// Block %#x, offset %#x", nr, boff) + var printnewline bool + for i := 0; i < blockSize; i++ { + if i%6 == 0 { + printnewline = true + } + v := 0 + if nn := n.table[i+offset]; nn != nil { + v = nn.value + } + if v != 0 { + if printnewline { + fmt.Printf("\n") + printnewline = false + } + fmt.Printf("%#04x:%#04x, ", boff+i, v) + } + } +} + +func printSparseBlock(nr int, n *trieNode) { + boff := -n.value + fmt.Printf("\n// Block %#x, offset %#x", nr, boff) + v := 0 + //stride := f(n) + stride := n.mostFrequentStride() + c := n.countSparseEntries() + fmt.Printf("\n{value:%#04x,lo:%#02x},", stride, uint8(c)) + for i, nn := range n.table[0x80 : 0x80+blockSize] { + nv := 0 + if nn != nil { + nv = nn.value + } + if nv-v != stride { + if v != 0 { + fmt.Printf(",hi:%#02x},", 0x80+i-1) + } + if nv != 0 { + fmt.Printf("\n{value:%#04x,lo:%#02x", nv, nn.b) + } + } + v = nv + } + if v != 0 { + fmt.Printf(",hi:%#02x},", 0x80+blockSize-1) + } +} + +func printLookupBlock(nr int, n *trieNode, offset, cutoff int) { + boff := nr * blockSize + fmt.Printf("\n// Block %#x, offset %#x", nr, boff) + var printnewline bool + for i := 0; i < blockSize; i++ { + if i%8 == 0 { + printnewline = true + } + v := 0 + if nn := n.table[i+offset]; nn != nil { + v = nn.value + } + if v != 0 { + if v < 0 { + v = -v - 1 + cutoff + } + if printnewline { + fmt.Printf("\n") + printnewline = false + } + fmt.Printf("%#03x:%#02x, ", boff+i, v) + } + } +} + +// printTables returns the size in bytes of the generated tables. +func (t *trieNode) printTables(name string) int { + index := newIndex() + // Values for 7-bit ASCII are stored in first two block, followed by nil block. + index.valueBlocks = append(index.valueBlocks, nil, nil, nil) + // First byte of multi-byte UTF-8 codepoints are indexed in 4th block. + index.lookupBlocks = append(index.lookupBlocks, nil, nil, nil, nil) + // Index starter bytes of multi-byte UTF-8. + for i := 0xC0; i < 0x100; i++ { + if t.table[i] != nil { + computeOffsets(index, t.table[i]) + } + } + + nv := len(index.valueBlocks) * blockSize + fmt.Printf("// %sValues: %d entries, %d bytes\n", name, nv, nv*2) + fmt.Printf("// Block 2 is the null block.\n") + fmt.Printf("var %sValues = [%d]uint16 {", name, nv) + printValueBlock(0, t, 0) + printValueBlock(1, t, 64) + printValueBlock(2, newNode(), 0) + for i := 3; i < len(index.valueBlocks); i++ { + printValueBlock(i, index.valueBlocks[i], 0x80) + } + fmt.Print("\n}\n\n") + + ls := len(index.sparseBlocks) + fmt.Printf("// %sSparseOffset: %d entries, %d bytes\n", name, ls, ls*2) + fmt.Printf("var %sSparseOffset = %#v\n\n", name, index.sparseOffset[1:]) + + ns := index.sparseCount + fmt.Printf("// %sSparseValues: %d entries, %d bytes\n", name, ns, ns*4) + fmt.Printf("var %sSparseValues = [%d]valueRange {", name, ns) + for i, n := range index.sparseBlocks { + printSparseBlock(i, n) + } + fmt.Print("\n}\n\n") + + cutoff := len(index.valueBlocks) - blockOffset + ni := len(index.lookupBlocks) * blockSize + fmt.Printf("// %sLookup: %d bytes\n", name, ni) + fmt.Printf("// Block 0 is the null block.\n") + fmt.Printf("var %sLookup = [%d]uint8 {", name, ni) + printLookupBlock(0, newNode(), 0, cutoff) + printLookupBlock(1, newNode(), 0, cutoff) + printLookupBlock(2, newNode(), 0, cutoff) + printLookupBlock(3, t, 0xC0, cutoff) + for i := 4; i < len(index.lookupBlocks); i++ { + printLookupBlock(i, index.lookupBlocks[i], 0x80, cutoff) + } + fmt.Print("\n}\n\n") + fmt.Printf("var %sTrie = trie{ %sLookup[:], %sValues[:], %sSparseValues[:], %sSparseOffset[:], %d}\n\n", + name, name, name, name, name, cutoff) + return nv*2 + ns*4 + ni + ls*2 +} diff --git a/Godeps/_workspace/src/github.com/calmh/ini/LICENSE b/Godeps/_workspace/src/github.com/calmh/ini/LICENSE new file mode 100644 index 000000000..fa5b4e205 --- /dev/null +++ b/Godeps/_workspace/src/github.com/calmh/ini/LICENSE @@ -0,0 +1,19 @@ +Copyright (C) 2013 Jakob Borg + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +- The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Godeps/_workspace/src/github.com/calmh/ini/README.md b/Godeps/_workspace/src/github.com/calmh/ini/README.md new file mode 100644 index 000000000..35791d76b --- /dev/null +++ b/Godeps/_workspace/src/github.com/calmh/ini/README.md @@ -0,0 +1,39 @@ +ini [![Build Status](https://drone.io/github.com/calmh/ini/status.png)](https://drone.io/github.com/calmh/ini/latest) +=== + +Yet another .INI file parser / writer. Created because the existing ones +were either not general enough (allowing easy access to all parts of the +original file) or made annoying assumptions about the format. And +probably equal parts NIH. You might want to just write your own instead +of using this one, you know that's where you'll end up in the end +anyhow. + +Documentation +------------- + +http://godoc.org/github.com/calmh/ini + +Example +------- + +```go +fd, _ := os.Open("foo.ini") +cfg := ini.Parse(fd) +fd.Close() + +val := cfg.Get("general", "foo") +cfg.Set("general", "bar", "baz") + +fd, _ = os.Create("bar.ini") +err := cfg.Write(fd) +if err != nil { + // ... +} +err = fd.Close() + +``` + +License +------- + +MIT diff --git a/Godeps/_workspace/src/github.com/calmh/ini/ini.go b/Godeps/_workspace/src/github.com/calmh/ini/ini.go new file mode 100644 index 000000000..808450c5e --- /dev/null +++ b/Godeps/_workspace/src/github.com/calmh/ini/ini.go @@ -0,0 +1,220 @@ +// Package ini provides trivial parsing of .INI format files. +package ini + +import ( + "bufio" + "fmt" + "io" + "regexp" + "strconv" + "strings" +) + +// Config is a parsed INI format file. +type Config struct { + sections []section + comments []string +} + +type section struct { + name string + comments []string + options []option +} + +type option struct { + name, value string +} + +var ( + iniSectionRe = regexp.MustCompile(`^\[(.+)\]$`) + iniOptionRe = regexp.MustCompile(`^([^\s=]+)\s*=\s*(.+?)$`) +) + +// Sections returns the list of sections in the file. +func (c *Config) Sections() []string { + var sections []string + for _, sect := range c.sections { + sections = append(sections, sect.name) + } + return sections +} + +// Options returns the list of options in a given section. +func (c *Config) Options(section string) []string { + var options []string + for _, sect := range c.sections { + if sect.name == section { + for _, opt := range sect.options { + options = append(options, opt.name) + } + break + } + } + return options +} + +// OptionMap returns the map option => value for a given section. +func (c *Config) OptionMap(section string) map[string]string { + options := make(map[string]string) + for _, sect := range c.sections { + if sect.name == section { + for _, opt := range sect.options { + options[opt.name] = opt.value + } + break + } + } + return options +} + +// Comments returns the list of comments in a given section. +// For the empty string, returns the file comments. +func (c *Config) Comments(section string) []string { + if section == "" { + return c.comments + } + for _, sect := range c.sections { + if sect.name == section { + return sect.comments + } + } + return nil +} + +// AddComments appends the comment to the list of comments for the section. +func (c *Config) AddComment(sect, comment string) { + if sect == "" { + c.comments = append(c.comments, comment) + return + } + + for i, s := range c.sections { + if s.name == sect { + c.sections[i].comments = append(s.comments, comment) + return + } + } + + c.sections = append(c.sections, section{ + name: sect, + comments: []string{comment}, + }) +} + +// Parse reads the given io.Reader and returns a parsed Config object. +func Parse(stream io.Reader) Config { + var cfg Config + var curSection string + + scanner := bufio.NewScanner(bufio.NewReader(stream)) + for scanner.Scan() { + line := strings.TrimSpace(scanner.Text()) + if strings.HasPrefix(line, "#") || strings.HasPrefix(line, ";") { + comment := strings.TrimLeft(line, ";# ") + cfg.AddComment(curSection, comment) + } else if len(line) > 0 { + if m := iniSectionRe.FindStringSubmatch(line); len(m) > 0 { + curSection = m[1] + } else if m := iniOptionRe.FindStringSubmatch(line); len(m) > 0 { + key := m[1] + val := m[2] + if !strings.Contains(val, "\"") { + // If val does not contain any quote characers, we can make it + // a quoted string and safely let strconv.Unquote sort out any + // escapes + val = "\"" + val + "\"" + } + if val[0] == '"' { + val, _ = strconv.Unquote(val) + } + + cfg.Set(curSection, key, val) + } + } + } + return cfg +} + +// Write writes the sections and options to the io.Writer in INI format. +func (c *Config) Write(out io.Writer) error { + for _, cmt := range c.comments { + fmt.Fprintln(out, "; "+cmt) + } + if len(c.comments) > 0 { + fmt.Fprintln(out) + } + + for _, sect := range c.sections { + fmt.Fprintf(out, "[%s]\n", sect.name) + for _, cmt := range sect.comments { + fmt.Fprintln(out, "; "+cmt) + } + for _, opt := range sect.options { + val := opt.value + if len(val) == 0 { + continue + } + + // Quote the string if it begins or ends with space + needsQuoting := val[0] == ' ' || val[len(val)-1] == ' ' + + if !needsQuoting { + // Quote the string if it contains any unprintable characters + for _, r := range val { + if !strconv.IsPrint(r) { + needsQuoting = true + break + } + } + } + + if needsQuoting { + val = strconv.Quote(val) + } + + fmt.Fprintf(out, "%s=%s\n", opt.name, val) + } + fmt.Fprintln(out) + } + return nil +} + +// Get gets the value from the specified section and key name, or the empty +// string if either the section or the key is missing. +func (c *Config) Get(section, key string) string { + for _, sect := range c.sections { + if sect.name == section { + for _, opt := range sect.options { + if opt.name == key { + return opt.value + } + } + return "" + } + } + return "" +} + +// Set sets a value for an option in a section. If the option exists, it's +// value will be overwritten. If the option does not exist, it will be added. +// If the section does not exist, it will be added and the option added to it. +func (c *Config) Set(sectionName, key, value string) { + for i, sect := range c.sections { + if sect.name == sectionName { + for j, opt := range sect.options { + if opt.name == key { + c.sections[i].options[j].value = value + return + } + } + c.sections[i].options = append(sect.options, option{key, value}) + return + } + } + + c.sections = append(c.sections, section{ + name: sectionName, + options: []option{{key, value}}, + }) +} diff --git a/Godeps/_workspace/src/github.com/calmh/ini/ini_test.go b/Godeps/_workspace/src/github.com/calmh/ini/ini_test.go new file mode 100644 index 000000000..4a313fe5a --- /dev/null +++ b/Godeps/_workspace/src/github.com/calmh/ini/ini_test.go @@ -0,0 +1,178 @@ +package ini_test + +import ( + "bytes" + "github.com/calmh/ini" + "strings" + "testing" +) + +func TestParseValues(t *testing.T) { + strs := []string{ + `[general]`, + `k1=v1`, + `k2 = v2`, + ` k3 = v3 `, + `k4=" quoted spaces "`, + `k5 = " quoted spaces " `, + `k6 = with\nnewline`, + `k7 = "with\nnewline"`, + `k8 = a "quoted" word`, + `k9 = "a \"quoted\" word"`, + } + buf := bytes.NewBufferString(strings.Join(strs, "\n")) + cfg := ini.Parse(buf) + + correct := map[string]string{ + "k1": "v1", + "k2": "v2", + "k3": "v3", + "k4": " quoted spaces ", + "k5": " quoted spaces ", + "k6": "with\nnewline", + "k7": "with\nnewline", + "k8": "a \"quoted\" word", + "k9": "a \"quoted\" word", + } + + for k, v := range correct { + if v2 := cfg.Get("general", k); v2 != v { + t.Errorf("Incorrect general.%s, %q != %q", k, v2, v) + } + } + + if v := cfg.Get("general", "nonexistant"); v != "" { + t.Errorf("Unexpected non-empty value %q", v) + } +} + +func TestParseComments(t *testing.T) { + strs := []string{ + ";file comment 1", // No leading space + "; file comment 2 ", // Trailing space + "; file comment 3", // Multiple leading spaces + "[general]", + "; b general comment 1", // Comments in unsorted order + "somekey = somevalue", + "; a general comment 2", + "[other]", + "; other comment 1", // Comments in section with no values + "; other comment 2", + "[other2]", + "; other2 comment 1", + "; other2 comment 2", // Comments on last section + "somekey = somevalue", + } + buf := bytes.NewBufferString(strings.Join(strs, "\n")) + + correct := map[string][]string{ + "": []string{"file comment 1", "file comment 2", "file comment 3"}, + "general": []string{"b general comment 1", "a general comment 2"}, + "other": []string{"other comment 1", "other comment 2"}, + "other2": []string{"other2 comment 1", "other2 comment 2"}, + } + + cfg := ini.Parse(buf) + + for section, comments := range correct { + cmts := cfg.Comments(section) + if len(cmts) != len(comments) { + t.Errorf("Incorrect number of comments for section %q: %d != %d", section, len(cmts), len(comments)) + } else { + for i := range comments { + if cmts[i] != comments[i] { + t.Errorf("Incorrect comment: %q != %q", cmts[i], comments[i]) + } + } + } + } +} + +func TestWrite(t *testing.T) { + cfg := ini.Config{} + cfg.Set("general", "k1", "v1") + cfg.Set("general", "k2", "foo bar") + cfg.Set("general", "k3", " foo bar ") + cfg.Set("general", "k4", "foo\nbar") + + var out bytes.Buffer + cfg.Write(&out) + + correct := `[general] +k1=v1 +k2=foo bar +k3=" foo bar " +k4="foo\nbar" + +` + if s := out.String(); s != correct { + t.Errorf("Incorrect written .INI:\n%s\ncorrect:\n%s", s, correct) + } +} + +func TestSet(t *testing.T) { + buf := bytes.NewBufferString("[general]\nfoo=bar\nfoo2=bar2\n") + cfg := ini.Parse(buf) + + cfg.Set("general", "foo", "baz") // Overwrite existing + cfg.Set("general", "baz", "quux") // Create new value + cfg.Set("other", "baz2", "quux2") // Create new section + value + + var out bytes.Buffer + cfg.Write(&out) + + correct := `[general] +foo=baz +foo2=bar2 +baz=quux + +[other] +baz2=quux2 + +` + + if s := out.String(); s != correct { + t.Errorf("Incorrect INI after set:\n%s", s) + } +} + +func TestSetManyEquals(t *testing.T) { + buf := bytes.NewBufferString("[general]\nfoo=bar==\nfoo2=bar2==\n") + cfg := ini.Parse(buf) + + cfg.Set("general", "foo", "baz==") + + var out bytes.Buffer + cfg.Write(&out) + + correct := `[general] +foo=baz== +foo2=bar2== + +` + + if s := out.String(); s != correct { + t.Errorf("Incorrect INI after set:\n%s", s) + } +} + +func TestRewriteDuplicate(t *testing.T) { + buf := bytes.NewBufferString("[general]\nfoo=bar==\nfoo=bar2==\n") + cfg := ini.Parse(buf) + + if v := cfg.Get("general", "foo"); v != "bar2==" { + t.Errorf("incorrect get %q", v) + } + + var out bytes.Buffer + cfg.Write(&out) + + correct := `[general] +foo=bar2== + +` + + if s := out.String(); s != correct { + t.Errorf("Incorrect INI after set:\n%s", s) + } +} diff --git a/Godeps/_workspace/src/github.com/codegangsta/inject/.gitignore b/Godeps/_workspace/src/github.com/codegangsta/inject/.gitignore new file mode 100644 index 000000000..df3df8a90 --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/inject/.gitignore @@ -0,0 +1,2 @@ +inject +inject.test diff --git a/Godeps/_workspace/src/github.com/codegangsta/inject/LICENSE b/Godeps/_workspace/src/github.com/codegangsta/inject/LICENSE new file mode 100644 index 000000000..eb68a0e05 --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/inject/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2013 Jeremy Saenz + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/Godeps/_workspace/src/github.com/codegangsta/inject/README.md b/Godeps/_workspace/src/github.com/codegangsta/inject/README.md new file mode 100644 index 000000000..1721ab4a8 --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/inject/README.md @@ -0,0 +1,4 @@ +inject +====== + +Dependency injection for go diff --git a/Godeps/_workspace/src/github.com/codegangsta/inject/inject.go b/Godeps/_workspace/src/github.com/codegangsta/inject/inject.go new file mode 100644 index 000000000..17d87081e --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/inject/inject.go @@ -0,0 +1,122 @@ +package inject + +import ( + "fmt" + "reflect" +) + +type Injector interface { + Applicator + Invoker + TypeMapper + SetParent(Injector) +} + +type Applicator interface { + Apply(interface{}) error +} + +type Invoker interface { + Invoke(interface{}) ([]reflect.Value, error) +} + +type TypeMapper interface { + Map(interface{}) TypeMapper + MapTo(interface{}, interface{}) TypeMapper + Get(reflect.Type) reflect.Value +} + +type injector struct { + values map[reflect.Type]reflect.Value + parent Injector +} + +func InterfaceOf(value interface{}) reflect.Type { + t := reflect.TypeOf(value) + + for t.Kind() == reflect.Ptr { + t = t.Elem() + } + + if t.Kind() != reflect.Interface { + panic("Called inject.InterfaceOf with a value that is not a pointer to an interface. (*MyInterface)(nil)") + } + + return t +} + +func New() Injector { + return &injector{ + values: make(map[reflect.Type]reflect.Value), + } +} + +func (inj *injector) Invoke(f interface{}) ([]reflect.Value, error) { + t := reflect.TypeOf(f) + + var in = make([]reflect.Value, t.NumIn()) + for i := 0; i < t.NumIn(); i++ { + argType := t.In(i) + val := inj.Get(argType) + if !val.IsValid() { + return nil, fmt.Errorf("Value not found for type %v", argType) + } + + in[i] = val + } + + return reflect.ValueOf(f).Call(in), nil +} + +func (inj *injector) Apply(val interface{}) error { + v := reflect.ValueOf(val) + + for v.Kind() == reflect.Ptr { + v = v.Elem() + } + + if v.Kind() != reflect.Struct { + return nil + } + + t := v.Type() + + for i := 0; i < v.NumField(); i++ { + f := v.Field(i) + structField := t.Field(i) + if f.CanSet() && structField.Tag == "inject" { + ft := f.Type() + v := inj.Get(ft) + if !v.IsValid() { + return fmt.Errorf("Value not found for type %v", ft) + } + + f.Set(v) + } + + } + + return nil +} + +func (i *injector) Map(val interface{}) TypeMapper { + i.values[reflect.TypeOf(val)] = reflect.ValueOf(val) + return i +} + +func (i *injector) MapTo(val interface{}, ifacePtr interface{}) TypeMapper { + i.values[InterfaceOf(ifacePtr)] = reflect.ValueOf(val) + return i +} + +func (i *injector) Get(t reflect.Type) reflect.Value { + val := i.values[t] + if !val.IsValid() && i.parent != nil { + val = i.parent.Get(t) + } + return val +} + +func (i *injector) SetParent(parent Injector) { + i.parent = parent +} diff --git a/Godeps/_workspace/src/github.com/codegangsta/inject/inject_test.go b/Godeps/_workspace/src/github.com/codegangsta/inject/inject_test.go new file mode 100644 index 000000000..ffcc174cd --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/inject/inject_test.go @@ -0,0 +1,112 @@ +package inject_test + +import ( + "github.com/codegangsta/inject" + "reflect" + "testing" +) + +type SpecialString interface { +} + +type TestStruct struct { + Dep1 string `inject` + Dep2 SpecialString `inject` + Dep3 string +} + +/* Test Helpers */ +func expect(t *testing.T, a interface{}, b interface{}) { + if a != b { + t.Errorf("Expected %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a)) + } +} + +func refute(t *testing.T, a interface{}, b interface{}) { + if a == b { + t.Errorf("Did not expect %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a)) + } +} + +func Test_InjectorInvoke(t *testing.T) { + injector := inject.New() + expect(t, injector == nil, false) + + dep := "some dependency" + injector.Map(dep) + dep2 := "another dep" + injector.MapTo(dep2, (*SpecialString)(nil)) + + _, err := injector.Invoke(func(d1 string, d2 SpecialString) { + expect(t, d1, dep) + expect(t, d2, dep2) + }) + + expect(t, err, nil) +} + +func Test_InjectorInvokeReturnValues(t *testing.T) { + injector := inject.New() + expect(t, injector == nil, false) + + dep := "some dependency" + injector.Map(dep) + dep2 := "another dep" + injector.MapTo(dep2, (*SpecialString)(nil)) + + result, err := injector.Invoke(func(d1 string, d2 SpecialString) string { + expect(t, d1, dep) + expect(t, d2, dep2) + return "Hello world" + }) + + expect(t, result[0].String(), "Hello world") + expect(t, err, nil) +} + +func Test_InjectorApply(t *testing.T) { + injector := inject.New() + + injector.Map("a dep").MapTo("another dep", (*SpecialString)(nil)) + + s := TestStruct{} + err := injector.Apply(&s) + expect(t, err, nil) + + expect(t, s.Dep1, "a dep") + expect(t, s.Dep2, "another dep") +} + +func Test_InterfaceOf(t *testing.T) { + iType := inject.InterfaceOf((*SpecialString)(nil)) + expect(t, iType.Kind(), reflect.Interface) + + iType = inject.InterfaceOf((**SpecialString)(nil)) + expect(t, iType.Kind(), reflect.Interface) + + // Expecting nil + defer func() { + rec := recover() + refute(t, rec, nil) + }() + iType = inject.InterfaceOf((*testing.T)(nil)) +} + +func Test_InjectorGet(t *testing.T) { + injector := inject.New() + + injector.Map("some dependency") + + expect(t, injector.Get(reflect.TypeOf("string")).IsValid(), true) + expect(t, injector.Get(reflect.TypeOf(11)).IsValid(), false) +} + +func Test_InjectorSetParent(t *testing.T) { + injector := inject.New() + injector.MapTo("another dep", (*SpecialString)(nil)) + + injector2 := inject.New() + injector2.SetParent(injector) + + expect(t, injector2.Get(inject.InterfaceOf((*SpecialString)(nil))).IsValid(), true) +} diff --git a/Godeps/_workspace/src/github.com/codegangsta/martini/.gitignore b/Godeps/_workspace/src/github.com/codegangsta/martini/.gitignore new file mode 100644 index 000000000..836562412 --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/martini/.gitignore @@ -0,0 +1,23 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test diff --git a/Godeps/_workspace/src/github.com/codegangsta/martini/LICENSE b/Godeps/_workspace/src/github.com/codegangsta/martini/LICENSE new file mode 100644 index 000000000..eb68a0e05 --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/martini/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2013 Jeremy Saenz + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/Godeps/_workspace/src/github.com/codegangsta/martini/README.md b/Godeps/_workspace/src/github.com/codegangsta/martini/README.md new file mode 100644 index 000000000..bdece746e --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/martini/README.md @@ -0,0 +1,303 @@ +# Martini [![Build Status](https://drone.io/github.com/codegangsta/martini/status.png)](https://drone.io/github.com/codegangsta/martini/latest) [![GoDoc](https://godoc.org/github.com/codegangsta/martini?status.png)](http://godoc.org/github.com/codegangsta/martini) + +Martini is a powerful package for quickly writing modular web applications/services in Golang. + +## Getting Started + +After installing Go and setting up your [GOPATH](http://golang.org/doc/code.html#GOPATH), create your first `.go` file. We'll call it `server.go`. + +~~~ go +package main + +import "github.com/codegangsta/martini" + +func main() { + m := martini.Classic() + m.Get("/", func() string { + return "Hello world!" + }) + m.Run() +} +~~~ + +Then install the Martini package (**go 1.1** and greater is required): +~~~ +go get github.com/codegangsta/martini +~~~ + +Then run your server: +~~~ +go run server.go +~~~ + +You will now have a Martini webserver running on `localhost:3000`. + +## Getting Help + +Join the [Mailing list](https://groups.google.com/forum/#!forum/martini-go) + +Watch the [Demo Video](http://martini.codegangsta.io/#demo) + +## Features +* Extremely simple to use. +* Non-intrusive design. +* Play nice with other Golang packages. +* Awesome path matching and routing. +* Modular design - Easy to add functionality, easy to rip stuff out. +* Lots of good handlers/middlewares to use. +* Great 'out of the box' feature set. +* **Fully compatible with the [http.HandlerFunc](http://godoc.org/net/http#HandlerFunc) interface.** + +## More Middleware +For more middleware and functionality, check out the [martini-contrib](http://github.com/codegangsta/martini-contrib) repository. + +## Table of Contents +* [Classic Martini](#classic-martini) + * [Handlers](#handlers) + * [Routing](#routing) + * [Services](#services) + * [Serving Static Files](#serving-static-files) +* [Middleware Handlers](#middleware-handlers) + * [Next()](#next) +* [FAQ](#faq) + +## Classic Martini +To get up and running quickly, [martini.Classic()](http://godoc.org/github.com/codegangsta/martini#Classic) provides some reasonable defaults that work well for most web applications: +~~~ go + m := martini.Classic() + // ... middleware and routing goes here + m.Run() +~~~ + +Below is some of the functionality [martini.Classic()](http://godoc.org/github.com/codegangsta/martini#Classic) pulls in automatically: + * Request/Response Logging - [martini.Logger](http://godoc.org/github.com/codegangsta/martini#Logger) + * Panic Recovery - [martini.Recovery](http://godoc.org/github.com/codegangsta/martini#Recovery) + * Static File serving - [martini.Static](http://godoc.org/github.com/codegangsta/martini#Static) + * Routing - [martini.Router](http://godoc.org/github.com/codegangsta/martini#Router) + +### Handlers +Handlers are the heart and soul of Martini. A handler is basically any kind of callable function: +~~~ go +m.Get("/", func() { + println("hello world") +}) +~~~ + +#### Return Values +If a handler returns something, Martini will write the result to the current [http.ResponseWriter](http://godoc.org/net/http#ResponseWriter) as a string: +~~~ go +m.Get("/", func() string { + return "hello world" // HTTP 200 : "hello world" +}) +~~~ + +You can also optionally return a status code: +~~~ go +m.Get("/", func() (int, string) { + return 418, "i'm a teapot" // HTTP 418 : "i'm a teapot" +}) +~~~ + +#### Service Injection +Handlers are invoked via reflection. Martini makes use of *Dependency Injection* to resolve dependencies in a Handlers argument list. **This makes Martini completely compatible with golang's `http.HandlerFunc` interface.** + +If you add an argument to your Handler, Martini will search it's list of services and attempt to resolve the dependency via type assertion: +~~~ go +m.Get("/", func(res http.ResponseWriter, req *http.Request) { // res and req are injected by Martini + res.WriteHeader(200) // HTTP 200 +}) +~~~ + +The following services are included with [martini.Classic()](http://godoc.org/github.com/codegangsta/martini#Classic): + * [*log.Logger](http://godoc.org/log#Logger) - Global logger for Martini. + * [martini.Context](http://godoc.org/github.com/codegangsta/martini#Context) - http request context. + * [martini.Params](http://godoc.org/github.com/codegangsta/martini#Params) - `map[string]string` of named params found by route matching. + * [martini.Routes](http://godoc.org/github.com/codegangsta/martini#Routes) - Route helper service. + * [http.ResponseWriter](http://godoc.org/net/http/#ResponseWriter) - http Response writer interface. + * [*http.Request](http://godoc.org/net/http/#Request) - http Request. + +### Routing +In Martini, a route is an HTTP method paired with a URL-matching pattern. +Each route can take one or more handler methods: +~~~ go +m.Get("/", func() { + // show something +}) + +m.Patch("/", func() { + // update something +}) + +m.Post("/", func() { + // create something +}) + +m.Put("/", func() { + // replace something +}) + +m.Delete("/", func() { + // destroy something +}) + +m.Options("/", func() { + // http options +}) + +m.NotFound(func() { + // handle 404 +}) +~~~ + +Routes are matched in the order they are defined. The first route that +matches the request is invoked. + +Route patterns may include named parameters, accessible via the [martini.Params](http://godoc.org/github.com/codegangsta/martini#Params) service: +~~~ go +m.Get("/hello/:name", func(params martini.Params) string { + return "Hello " + params["name"] +}) +~~~ + +Routes can be matched with regular expressions and globs as well: +~~~ go +m.Get("/hello/**", func(params martini.Params) string { + return "Hello " + params["_1"] +}) +~~~ + +Route handlers can be stacked on top of each other, which is useful for things like authentication and authorization: +~~~ go +m.Get("/secret", authorize, func() { + // this will execute as long as authorize doesn't write a response +}) +~~~ + +### Services +Services are objects that are available to be injected into a Handler's argument list. You can map a service on a *Global* or *Request* level. + +#### Global Mapping +A Martini instance implements the inject.Injector interface, so mapping a service is easy: +~~~ go +db := &MyDatabase{} +m := martini.Classic() +m.Map(db) // the service will be available to all handlers as *MyDatabase +// ... +m.Run() +~~~ + +#### Request-Level Mapping +Mapping on the request level can be done in a handler via [martini.Context](http://godoc.org/github.com/codegangsta/martini#Context): +~~~ go +func MyCustomLoggerHandler(c martini.Context, req *http.Request) { + logger := &MyCustomLogger{req} + c.Map(logger) // mapped as *MyCustomLogger +} +~~~ + +#### Mapping values to Interfaces +One of the most powerful parts about services is the ability to map a service to an interface. For instance, if you wanted to override the [http.ResponseWriter](http://godoc.org/net/http#ResponseWriter) with an object that wrapped it and performed extra operations, you can write the following handler: +~~~ go +func WrapResponseWriter(res http.ResponseWriter, c martini.Context) { + rw := NewSpecialResponseWriter(res) + c.MapTo(rw, (*http.ResponseWriter)(nil)) // override ResponseWriter with our wrapper ResponseWriter +} +~~~ + +### Serving Static Files +A [martini.Classic()](http://godoc.org/github.com/codegangsta/martini#Classic) instance automatically serves static files from the "public" directory in the root of your server. +You can serve from more directories by adding more [martini.Static](http://godoc.org/github.com/codegangsta/martini#Static) handlers. +~~~ go +m.Use(martini.Static("assets")) // serve from the "assets" directory as well +~~~ + +## Middleware Handlers +Middleware Handlers sit between the incoming http request and the router. In essence they are no different than any other Handler in Martini. You can add a middleware handler to the stack like so: +~~~ go +m.Use(func() { + // do some middleware stuff +}) +~~~ + +You can have full control over the middleware stack with the `Handlers` function: +~~~ go +m.Handlers( + Middleware1, + Middleware2, + Middleware3, +) +~~~ + +Middleware Handlers work really well for things like logging, authorization, authentication, sessions, gzipping, error pages and any other operations that must happen before or after an http request: +~~~ go +// validate an api key +m.Use(func(res http.ResponseWriter, req *http.Request) { + if req.Header.Get("X-API-KEY") != "secret123" { + res.WriteHeader(http.StatusUnauthorized) + } +}) +~~~ + +### Next() +[Context.Next()](http://godoc.org/github.com/codegangsta/martini#Context) is an optional function that Middleware Handlers can call to yield the until after the other Handlers have been executed. This works really well for any operations that must happen after an http request: +~~~ go +// log before and after a request +m.Use(func(c martini.Context, log *log.Logger){ + log.Println("before a request") + + c.Next() + + log.Println("after a request") +}) +~~~ + +## FAQ + +### Where do I find middleware X? + +Start by looking in the [martini-contrib](http://github.com/codegangsta/martini-contrib) package. If it is not there feel free to put up a Pull Request for one. + +* [auth](https://github.com/codegangsta/martini-contrib/tree/master/auth) - Handlers for authentication. +* [form](https://github.com/codegangsta/martini-contrib/tree/master/form) - Handler for parsing and mapping form fields. +* [gzip](https://github.com/codegangsta/martini-contrib/tree/master/gzip) - Handler for adding gzip compress to requests +* [render](https://github.com/codegangsta/martini-contrib/tree/master/render) - Handler that provides a service for easily rendering JSON and HTML templates. +* [acceptlang](https://github.com/codegangsta/martini-contrib/tree/master/acceptlang) - Handler for parsing the `Accept-Language` HTTP header. + +### How do I integrate with existing servers? + +A Martini instance implements `http.Handler`, so it can easily be used to serve subtrees +on existing Go servers. For example this is a working Martini app for Google App Engine: + +~~~ go +package hello + +import ( + "net/http" + "github.com/codegangsta/martini" +) + +func init() { + m := martini.Classic() + m.Get("/", func() string { + return "Hello world!" + }) + http.Handle("/", m) +} +~~~ + +### How do I change the port/host? + +Martini's `Run` function looks for the PORT environment variable and uses that. Otherwise Martini will default to port 3000. +To have more flexibility over port and host, use the `http.ListenAndServe` function instead. + +~~~ go + m := martini.Classic() + // ... + http.ListenAndServe(":8080", m) +~~~ + +## Contributing +Martini is meant to be kept tiny and clean. Most contributions should end up in the [martini-contrib](http://github.com/codegangsta/martini-contrib) repository. If you do have a contribution for the core of Martini feel free to put up a Pull Request. + +## About +Martini is obsessively designed by none other than the [Code Gangsta](http://codegangsta.io/) diff --git a/Godeps/_workspace/src/github.com/codegangsta/martini/env.go b/Godeps/_workspace/src/github.com/codegangsta/martini/env.go new file mode 100644 index 000000000..250a99161 --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/martini/env.go @@ -0,0 +1,21 @@ +package martini + +import ( + "os" +) + +const ( + Dev string = "development" + Prod string = "production" + Test string = "test" +) + +// Env is the environment that Martini is executing in. The MARTINI_ENV is read on initialization to set this variable. +var Env string = Dev + +func init() { + e := os.Getenv("MARTINI_ENV") + if len(e) > 0 { + Env = e + } +} diff --git a/Godeps/_workspace/src/github.com/codegangsta/martini/go_version.go b/Godeps/_workspace/src/github.com/codegangsta/martini/go_version.go new file mode 100644 index 000000000..e76fe162e --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/martini/go_version.go @@ -0,0 +1,3 @@ +// +build !go1.1 + +"martini requires go 1.1 or greater to build" diff --git a/Godeps/_workspace/src/github.com/codegangsta/martini/logger.go b/Godeps/_workspace/src/github.com/codegangsta/martini/logger.go new file mode 100644 index 000000000..ff9d91a1f --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/martini/logger.go @@ -0,0 +1,22 @@ +package martini + +import ( + "log" + "net/http" + "time" +) + +// Logger returns a middleware handler that logs the request as it goes in and the response as it goes out. +func Logger() Handler { + return func(res http.ResponseWriter, req *http.Request, c Context, log *log.Logger) { + start := time.Now() + log.Printf("Started %s %s", req.Method, req.URL.Path) + + rw := NewResponseWriter(res) + c.MapTo(rw, (*http.ResponseWriter)(nil)) + + c.Next() + + log.Printf("Completed %v %s in %v\n", rw.Status(), http.StatusText(rw.Status()), time.Since(start)) + } +} diff --git a/Godeps/_workspace/src/github.com/codegangsta/martini/logger_test.go b/Godeps/_workspace/src/github.com/codegangsta/martini/logger_test.go new file mode 100644 index 000000000..156b14926 --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/martini/logger_test.go @@ -0,0 +1,31 @@ +package martini + +import ( + "bytes" + "log" + "net/http" + "net/http/httptest" + "testing" +) + +func Test_Logger(t *testing.T) { + buff := bytes.NewBufferString("") + recorder := httptest.NewRecorder() + + m := New() + // replace log for testing + m.Map(log.New(buff, "[martini] ", 0)) + m.Use(Logger()) + m.Use(func(res http.ResponseWriter) { + res.WriteHeader(http.StatusNotFound) + }) + + req, err := http.NewRequest("GET", "http://localhost:3000/foobar", nil) + if err != nil { + t.Error(err) + } + + m.ServeHTTP(recorder, req) + expect(t, recorder.Code, http.StatusNotFound) + refute(t, len(buff.String()), 0) +} diff --git a/Godeps/_workspace/src/github.com/codegangsta/martini/martini.go b/Godeps/_workspace/src/github.com/codegangsta/martini/martini.go new file mode 100644 index 000000000..5a71c84dc --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/martini/martini.go @@ -0,0 +1,155 @@ +// Package martini is a powerful package for quickly writing modular web applications/services in Golang. +// +// For a full guide visit http://github.com/codegangsta/martini +// +// package main +// +// import "github.com/codegangsta/martini" +// +// func main() { +// m := martini.Classic() +// +// m.Get("/", func() string { +// return "Hello world!" +// }) +// +// m.Run() +// } +package martini + +import ( + "github.com/codegangsta/inject" + "log" + "net/http" + "os" + "reflect" +) + +// Martini represents the top level web application. inject.Injector methods can be invoked to map services on a global level. +type Martini struct { + inject.Injector + handlers []Handler + action Handler + logger *log.Logger +} + +// New creates a bare bones Martini instance. Use this method if you want to have full control over the middleware that is used. +func New() *Martini { + m := &Martini{inject.New(), []Handler{}, func() {}, log.New(os.Stdout, "[martini] ", 0)} + m.Map(m.logger) + return m +} + +// Use adds a middleware Handler to the stack. Will panic if the handler is not a callable func. Middleware Handlers are invoked in the order that they are added. +func (m *Martini) Use(handler Handler) { + validateHandler(handler) + + m.handlers = append(m.handlers, handler) +} + +// ServeHTTP is the HTTP Entry point for a Martini instance. Useful if you want to control your own HTTP server. +func (m *Martini) ServeHTTP(res http.ResponseWriter, req *http.Request) { + m.createContext(res, req).run() +} + +// Action sets the handler that will be called after all the middleware has been invoked. This is set to martini.Router in a martini.Classic(). +func (m *Martini) Action(handler Handler) { + validateHandler(handler) + m.action = handler +} + +// Run the http server. Listening on os.GetEnv("PORT") or 3000 by default. +func (m *Martini) Run() { + port := os.Getenv("PORT") + if len(port) == 0 { + port = "3000" + } + + m.logger.Println("listening on port " + port) + m.logger.Fatalln(http.ListenAndServe(":"+port, m)) +} + +// Handlers sets the entire middleware stack with the given Handlers. This will clear any current middleware handlers. +// Will panic if any of the handlers is not a callable function +func (m *Martini) Handlers(handlers ...Handler) { + m.handlers = make([]Handler, 0) + for _, handler := range handlers { + m.Use(handler) + } +} + +func (m *Martini) createContext(res http.ResponseWriter, req *http.Request) *context { + c := &context{inject.New(), append(m.handlers, m.action), NewResponseWriter(res), 0} + c.SetParent(m) + c.MapTo(c, (*Context)(nil)) + c.MapTo(c.rw, (*http.ResponseWriter)(nil)) + c.Map(req) + return c +} + +// ClassicMartini represents a Martini with some reasonable defaults. Embeds the router functions for convenience. +type ClassicMartini struct { + *Martini + Router +} + +// Classic creates a classic Martini with some basic default middleware - martini.Logger, martini.Recovery, and martini.Static. +func Classic() *ClassicMartini { + r := NewRouter() + m := New() + m.Use(Logger()) + m.Use(Recovery()) + m.Use(Static("public")) + m.Action(r.Handle) + return &ClassicMartini{m, r} +} + +// Handler can be any callable function. Martini attempts to inject services into the handler's argument list. +// Martini will panic if an argument could not be fullfilled via dependency injection. +type Handler interface{} + +func validateHandler(handler Handler) { + if reflect.TypeOf(handler).Kind() != reflect.Func { + panic("martini handler must be a callable func") + } +} + +// Context represents a request context. Services can be mapped on the request level from this interface. +type Context interface { + inject.Injector + // Next is an optional function that Middleware Handlers can call to yield the until after + // the other Handlers have been executed. This works really well for any operations that must + // happen after an http request + Next() + written() bool +} + +type context struct { + inject.Injector + handlers []Handler + rw ResponseWriter + index int +} + +func (c *context) Next() { + c.index += 1 + c.run() +} + +func (c *context) written() bool { + return c.rw.Written() +} + +func (c *context) run() { + for c.index < len(c.handlers) { + _, err := c.Invoke(c.handlers[c.index]) + if err != nil { + panic(err) + } + c.index += 1 + + if c.rw.Written() { + return + } + } +} diff --git a/Godeps/_workspace/src/github.com/codegangsta/martini/martini_test.go b/Godeps/_workspace/src/github.com/codegangsta/martini/martini_test.go new file mode 100644 index 000000000..ba5a65c13 --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/martini/martini_test.go @@ -0,0 +1,105 @@ +package martini + +import ( + "net/http" + "net/http/httptest" + "reflect" + "testing" +) + +/* Test Helpers */ +func expect(t *testing.T, a interface{}, b interface{}) { + if a != b { + t.Errorf("Expected %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a)) + } +} + +func refute(t *testing.T, a interface{}, b interface{}) { + if a == b { + t.Errorf("Did not expect %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a)) + } +} + +func Test_New(t *testing.T) { + m := New() + refute(t, m, nil) +} + +func Test_Martini_ServeHTTP(t *testing.T) { + result := "" + response := httptest.NewRecorder() + + m := New() + m.Use(func(c Context) { + result += "foo" + c.Next() + result += "ban" + }) + m.Use(func(c Context) { + result += "bar" + c.Next() + result += "baz" + }) + m.Action(func(res http.ResponseWriter, req *http.Request) { + result += "bat" + res.WriteHeader(http.StatusBadRequest) + }) + + m.ServeHTTP(response, (*http.Request)(nil)) + + expect(t, result, "foobarbatbazban") + expect(t, response.Code, http.StatusBadRequest) +} + +func Test_Martini_Handlers(t *testing.T) { + result := "" + response := httptest.NewRecorder() + + batman := func(c Context) { + result += "batman!" + } + + m := New() + m.Use(func(c Context) { + result += "foo" + c.Next() + result += "ban" + }) + m.Handlers( + batman, + batman, + batman, + ) + m.Action(func(res http.ResponseWriter, req *http.Request) { + result += "bat" + res.WriteHeader(http.StatusBadRequest) + }) + + m.ServeHTTP(response, (*http.Request)(nil)) + + expect(t, result, "batman!batman!batman!bat") + expect(t, response.Code, http.StatusBadRequest) +} + +func Test_Martini_EarlyWrite(t *testing.T) { + result := "" + response := httptest.NewRecorder() + + m := New() + m.Use(func(res http.ResponseWriter) { + result += "foobar" + res.Write([]byte("Hello world")) + }) + m.Use(func() { + result += "bat" + }) + m.Action(func(res http.ResponseWriter) { + result += "baz" + res.WriteHeader(http.StatusBadRequest) + }) + + m.ServeHTTP(response, (*http.Request)(nil)) + + expect(t, result, "foobar") + expect(t, response.Code, http.StatusOK) +} diff --git a/Godeps/_workspace/src/github.com/codegangsta/martini/recovery.go b/Godeps/_workspace/src/github.com/codegangsta/martini/recovery.go new file mode 100644 index 000000000..f93a6cee3 --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/martini/recovery.go @@ -0,0 +1,21 @@ +package martini + +import ( + "log" + "net/http" + "runtime/debug" +) + +// Recovery returns a middleware that recovers from any panics and writes a 500 if there was one. +func Recovery() Handler { + return func(res http.ResponseWriter, c Context, logger *log.Logger) { + defer func() { + if err := recover(); err != nil { + res.WriteHeader(http.StatusInternalServerError) + logger.Printf("PANIC: %s\n%s", err, debug.Stack()) + } + }() + + c.Next() + } +} diff --git a/Godeps/_workspace/src/github.com/codegangsta/martini/recovery_test.go b/Godeps/_workspace/src/github.com/codegangsta/martini/recovery_test.go new file mode 100644 index 000000000..0c31d32ca --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/martini/recovery_test.go @@ -0,0 +1,26 @@ +package martini + +import ( + "bytes" + "log" + "net/http" + "net/http/httptest" + "testing" +) + +func Test_Recovery(t *testing.T) { + buff := bytes.NewBufferString("") + recorder := httptest.NewRecorder() + + m := New() + // replace log for testing + m.Map(log.New(buff, "[martini] ", 0)) + m.Use(Recovery()) + m.Use(func(res http.ResponseWriter, req *http.Request) { + panic("here is a panic!") + }) + m.ServeHTTP(recorder, (*http.Request)(nil)) + expect(t, recorder.Code, http.StatusInternalServerError) + refute(t, len(buff.String()), 0) + +} diff --git a/Godeps/_workspace/src/github.com/codegangsta/martini/response_writer.go b/Godeps/_workspace/src/github.com/codegangsta/martini/response_writer.go new file mode 100644 index 000000000..645e2e381 --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/martini/response_writer.go @@ -0,0 +1,67 @@ +package martini + +import ( + "bufio" + "fmt" + "net" + "net/http" +) + +// ResponseWriter is a wrapper around http.ResponseWriter that provides extra information about +// the response. It is recommended that middleware handlers use this construct to wrap a responsewriter +// if the functionality calls for it. +type ResponseWriter interface { + http.ResponseWriter + // Status returns the status code of the response or 0 if the response has not been written. + Status() int + // Written returns whether or not the ResponseWriter has been written. + Written() bool + // Size returns the size of the response body. + Size() int +} + +// NewResponseWriter creates a ResponseWriter that wraps an http.ResponseWriter +func NewResponseWriter(rw http.ResponseWriter) ResponseWriter { + return &responseWriter{rw, 0, 0} +} + +type responseWriter struct { + http.ResponseWriter + status int + size int +} + +func (rw *responseWriter) WriteHeader(s int) { + rw.ResponseWriter.WriteHeader(s) + rw.status = s +} + +func (rw *responseWriter) Write(b []byte) (int, error) { + if !rw.Written() { + // The status will be StatusOK if WriteHeader has not been called yet + rw.status = http.StatusOK + } + size, err := rw.ResponseWriter.Write(b) + rw.size += size + return size, err +} + +func (rw *responseWriter) Status() int { + return rw.status +} + +func (rw *responseWriter) Size() int { + return rw.size +} + +func (rw *responseWriter) Written() bool { + return rw.status != 0 +} + +func (rw *responseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) { + hijacker, ok := rw.ResponseWriter.(http.Hijacker) + if !ok { + return nil, nil, fmt.Errorf("ResponseWriter doesn't support Hijacker interface") + } + return hijacker.Hijack() +} diff --git a/Godeps/_workspace/src/github.com/codegangsta/martini/response_writer_test.go b/Godeps/_workspace/src/github.com/codegangsta/martini/response_writer_test.go new file mode 100644 index 000000000..96f3af859 --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/martini/response_writer_test.go @@ -0,0 +1,76 @@ +package martini + +import ( + "bufio" + "net" + "net/http" + "net/http/httptest" + "testing" +) + +type hijackableResponse struct { + Hijacked bool +} + +func newHijackableResponse() *hijackableResponse { + return &hijackableResponse{} +} + +func (h *hijackableResponse) Header() http.Header { return nil } +func (h *hijackableResponse) Write(buf []byte) (int, error) { return 0, nil } +func (h *hijackableResponse) WriteHeader(code int) {} +func (h *hijackableResponse) Flush() {} +func (h *hijackableResponse) Hijack() (net.Conn, *bufio.ReadWriter, error) { + h.Hijacked = true + return nil, nil, nil +} + +func Test_ResponseWriter_WritingString(t *testing.T) { + rec := httptest.NewRecorder() + rw := NewResponseWriter(rec) + + rw.Write([]byte("Hello world")) + + expect(t, rec.Code, rw.Status()) + expect(t, rec.Body.String(), "Hello world") + expect(t, rw.Status(), http.StatusOK) + expect(t, rw.Size(), 11) + expect(t, rw.Written(), true) +} + +func Test_ResponseWriter_WritingStrings(t *testing.T) { + rec := httptest.NewRecorder() + rw := NewResponseWriter(rec) + + rw.Write([]byte("Hello world")) + rw.Write([]byte("foo bar bat baz")) + + expect(t, rec.Code, rw.Status()) + expect(t, rec.Body.String(), "Hello worldfoo bar bat baz") + expect(t, rw.Status(), http.StatusOK) + expect(t, rw.Size(), 26) +} + +func Test_ResponseWriter_WritingHeader(t *testing.T) { + rec := httptest.NewRecorder() + rw := NewResponseWriter(rec) + + rw.WriteHeader(http.StatusNotFound) + + expect(t, rec.Code, rw.Status()) + expect(t, rec.Body.String(), "") + expect(t, rw.Status(), http.StatusNotFound) + expect(t, rw.Size(), 0) +} + +func Test_ResponseWriter_Hijack(t *testing.T) { + hijackable := newHijackableResponse() + rw := NewResponseWriter(hijackable) + hijacker, ok := rw.(http.Hijacker) + expect(t, ok, true) + _, _, err := hijacker.Hijack() + if err != nil { + t.Error(err) + } + expect(t, hijackable.Hijacked, true) +} diff --git a/Godeps/_workspace/src/github.com/codegangsta/martini/router.go b/Godeps/_workspace/src/github.com/codegangsta/martini/router.go new file mode 100644 index 000000000..19bd79fe8 --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/martini/router.go @@ -0,0 +1,255 @@ +package martini + +import ( + "fmt" + "github.com/codegangsta/inject" + "net/http" + "reflect" + "regexp" + "strconv" +) + +// Params is a map of name/value pairs for named routes. An instance of martini.Params is available to be injected into any route handler. +type Params map[string]string + +// Router is Martini's de-facto routing interface. Supports HTTP verbs, stacked handlers, and dependency injection. +type Router interface { + // Get adds a route for a HTTP GET request to the specified matching pattern. + Get(string, ...Handler) Route + // Patch adds a route for a HTTP PATCH request to the specified matching pattern. + Patch(string, ...Handler) Route + // Post adds a route for a HTTP POST request to the specified matching pattern. + Post(string, ...Handler) Route + // Put adds a route for a HTTP PUT request to the specified matching pattern. + Put(string, ...Handler) Route + // Delete adds a route for a HTTP DELETE request to the specified matching pattern. + Delete(string, ...Handler) Route + // Options adds a route for a HTTP OPTIONS request to the specified matching pattern. + Options(string, ...Handler) Route + // Any adds a route for any HTTP method request to the specified matching pattern. + Any(string, ...Handler) Route + + // NotFound sets the handler that is called when a no route matches a request. Throws a basic 404 by default. + NotFound(Handler) + + // Handle is the entry point for routing. This is used as a martini.Handler + Handle(http.ResponseWriter, *http.Request, Context) +} + +type router struct { + routes []*route + notFound Handler +} + +// NewRouter creates a new Router instance. +func NewRouter() Router { + return &router{notFound: http.NotFound} +} + +func (r *router) Get(pattern string, h ...Handler) Route { + return r.addRoute("GET", pattern, h) +} + +func (r *router) Patch(pattern string, h ...Handler) Route { + return r.addRoute("PATCH", pattern, h) +} + +func (r *router) Post(pattern string, h ...Handler) Route { + return r.addRoute("POST", pattern, h) +} + +func (r *router) Put(pattern string, h ...Handler) Route { + return r.addRoute("PUT", pattern, h) +} + +func (r *router) Delete(pattern string, h ...Handler) Route { + return r.addRoute("DELETE", pattern, h) +} + +func (r *router) Options(pattern string, h ...Handler) Route { + return r.addRoute("OPTIONS", pattern, h) +} + +func (r *router) Any(pattern string, h ...Handler) Route { + return r.addRoute("*", pattern, h) +} + +func (r *router) Handle(res http.ResponseWriter, req *http.Request, context Context) { + for _, route := range r.routes { + ok, vals := route.Match(req.Method, req.URL.Path) + if ok { + params := Params(vals) + context.Map(params) + r := routes{} + context.MapTo(r, (*Routes)(nil)) + _, err := context.Invoke(route.Handle) + if err != nil { + panic(err) + } + return + } + } + + // no routes exist, 404 + _, err := context.Invoke(r.notFound) + if err != nil { + panic(err) + } +} + +func (r *router) NotFound(handler Handler) { + r.notFound = handler +} + +func (r *router) addRoute(method string, pattern string, handlers []Handler) *route { + route := newRoute(method, pattern, handlers) + route.Validate() + r.routes = append(r.routes, route) + return route +} + +// Route is an interface representing a Route in Martini's routing layer. +type Route interface { + // URLWith returns a rendering of the Route's url with the given string params. + URLWith([]string) string +} + +type route struct { + method string + regex *regexp.Regexp + handlers []Handler + pattern string +} + +func newRoute(method string, pattern string, handlers []Handler) *route { + route := route{method, nil, handlers, pattern} + r := regexp.MustCompile(`:[^/#?()\.\\]+`) + pattern = r.ReplaceAllStringFunc(pattern, func(m string) string { + return fmt.Sprintf(`(?P<%s>[^/#?]+)`, m[1:]) + }) + r2 := regexp.MustCompile(`\*\*`) + var index int + pattern = r2.ReplaceAllStringFunc(pattern, func(m string) string { + index++ + return fmt.Sprintf(`(?P<_%d>[^#?]*)`, index) + }) + pattern += `\/?` + route.regex = regexp.MustCompile(pattern) + return &route +} + +func (r route) Match(method string, path string) (bool, map[string]string) { + // add Any method matching support + if r.method != "*" && method != r.method { + return false, nil + } + + matches := r.regex.FindStringSubmatch(path) + if len(matches) > 0 && matches[0] == path { + params := make(map[string]string) + for i, name := range r.regex.SubexpNames() { + if len(name) > 0 { + params[name] = matches[i] + } + } + return true, params + } + return false, nil +} + +func (r *route) Validate() { + for _, handler := range r.handlers { + validateHandler(handler) + } +} + +func (r *route) Handle(c Context, res http.ResponseWriter) { + context := &routeContext{c, 0, r.handlers} + c.MapTo(context, (*Context)(nil)) + context.run() +} + +// URLWith returns the url pattern replacing the parameters for its values +func (r *route) URLWith(args []string) string { + if len(args) > 0 { + reg := regexp.MustCompile(`:[^/#?()\.\\]+`) + argCount := len(args) + i := 0 + url := reg.ReplaceAllStringFunc(r.pattern, func(m string) string { + var val interface{} + if i < argCount { + val = args[i] + } else { + val = m + } + i += 1 + return fmt.Sprintf(`%v`, val) + }) + + return url + } + return r.pattern +} + +// Routes is a helper service for Martini's routing layer. +type Routes interface { + // URLFor returns a rendered URL for the given route. Optional params can be passed to fulfill named parameters in the route. + URLFor(route Route, params ...interface{}) string +} + +type routes struct{} + +// URLFor returns the url for the given route name. +func (r routes) URLFor(route Route, params ...interface{}) string { + var args []string + for _, param := range params { + switch v := param.(type) { + case int: + args = append(args, strconv.FormatInt(int64(v), 10)) + case string: + args = append(args, v) + default: + if v != nil { + panic("Arguments passed to UrlFor must be integers or strings") + } + } + } + + return route.URLWith(args) +} + +type routeContext struct { + Context + index int + handlers []Handler +} + +func (r *routeContext) Next() { + r.index += 1 + r.run() +} + +func (r *routeContext) run() { + for r.index < len(r.handlers) { + handler := r.handlers[r.index] + vals, err := r.Invoke(handler) + if err != nil { + panic(err) + } + r.index += 1 + + // if the handler returned something, write it to + // the http response + rv := r.Get(inject.InterfaceOf((*http.ResponseWriter)(nil))) + res := rv.Interface().(http.ResponseWriter) + if len(vals) > 1 && vals[0].Kind() == reflect.Int { + res.WriteHeader(int(vals[0].Int())) + res.Write([]byte(vals[1].String())) + } else if len(vals) > 0 { + res.Write([]byte(vals[0].String())) + } + if r.written() { + return + } + } +} diff --git a/Godeps/_workspace/src/github.com/codegangsta/martini/router_test.go b/Godeps/_workspace/src/github.com/codegangsta/martini/router_test.go new file mode 100644 index 000000000..2ad9c8912 --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/martini/router_test.go @@ -0,0 +1,277 @@ +package martini + +import ( + "net/http" + "net/http/httptest" + "testing" +) + +func Test_Routing(t *testing.T) { + router := NewRouter() + recorder := httptest.NewRecorder() + + req, err := http.NewRequest("GET", "http://localhost:3000/foo", nil) + if err != nil { + t.Error(err) + } + context := New().createContext(recorder, req) + + req2, err := http.NewRequest("POST", "http://localhost:3000/bar/bat", nil) + if err != nil { + t.Error(err) + } + context2 := New().createContext(recorder, req2) + + req3, err := http.NewRequest("DELETE", "http://localhost:3000/baz", nil) + if err != nil { + t.Error(err) + } + context3 := New().createContext(recorder, req3) + + req4, err := http.NewRequest("PATCH", "http://localhost:3000/bar/foo", nil) + if err != nil { + t.Error(err) + } + context4 := New().createContext(recorder, req4) + + req5, err := http.NewRequest("GET", "http://localhost:3000/fez/this/should/match", nil) + if err != nil { + t.Error(err) + } + context5 := New().createContext(recorder, req5) + + req6, err := http.NewRequest("PUT", "http://localhost:3000/pop/blah/blah/blah/bap/foo/", nil) + if err != nil { + t.Error(err) + } + context6 := New().createContext(recorder, req6) + + req7, err := http.NewRequest("DELETE", "http://localhost:3000/wap//pow", nil) + if err != nil { + t.Error(err) + } + context7 := New().createContext(recorder, req6) + + result := "" + router.Get("/foo", func(req *http.Request) { + result += "foo" + }) + router.Patch("/bar/:id", func(params Params) { + expect(t, params["id"], "foo") + result += "barfoo" + }) + router.Post("/bar/:id", func(params Params) { + expect(t, params["id"], "bat") + result += "barbat" + }) + router.Put("/fizzbuzz", func() { + result += "fizzbuzz" + }) + router.Delete("/bazzer", func(c Context) { + result += "baz" + }) + router.Get("/fez/**", func(params Params) { + expect(t, params["_1"], "this/should/match") + result += "fez" + }) + router.Put("/pop/**/bap/:id/**", func(params Params) { + expect(t, params["id"], "foo") + expect(t, params["_1"], "blah/blah/blah") + expect(t, params["_2"], "") + result += "popbap" + }) + router.Delete("/wap/**/pow", func(params Params) { + expect(t, params["_1"], "") + result += "wappow" + }) + + router.Handle(recorder, req, context) + router.Handle(recorder, req2, context2) + router.Handle(recorder, req3, context3) + router.Handle(recorder, req4, context4) + router.Handle(recorder, req5, context5) + router.Handle(recorder, req6, context6) + router.Handle(recorder, req7, context7) + expect(t, result, "foobarbatbarfoofezpopbapwappow") + expect(t, recorder.Code, http.StatusNotFound) + expect(t, recorder.Body.String(), "404 page not found\n") +} + +func Test_RouterHandlerStatusCode(t *testing.T) { + router := NewRouter() + router.Get("/foo", func() string { + return "foo" + }) + router.Get("/bar", func() (int, string) { + return http.StatusForbidden, "bar" + }) + router.Get("/baz", func() (string, string) { + return "baz", "BAZ!" + }) + + // code should be 200 if none is returned from the handler + recorder := httptest.NewRecorder() + req, err := http.NewRequest("GET", "http://localhost:3000/foo", nil) + if err != nil { + t.Error(err) + } + context := New().createContext(recorder, req) + router.Handle(recorder, req, context) + expect(t, recorder.Code, http.StatusOK) + expect(t, recorder.Body.String(), "foo") + + // if a status code is returned, it should be used + recorder = httptest.NewRecorder() + req, err = http.NewRequest("GET", "http://localhost:3000/bar", nil) + if err != nil { + t.Error(err) + } + context = New().createContext(recorder, req) + router.Handle(recorder, req, context) + expect(t, recorder.Code, http.StatusForbidden) + expect(t, recorder.Body.String(), "bar") + + // shouldn't use the first returned value as a status code if not an integer + recorder = httptest.NewRecorder() + req, err = http.NewRequest("GET", "http://localhost:3000/baz", nil) + if err != nil { + t.Error(err) + } + context = New().createContext(recorder, req) + router.Handle(recorder, req, context) + expect(t, recorder.Code, http.StatusOK) + expect(t, recorder.Body.String(), "baz") +} + +func Test_RouterHandlerStacking(t *testing.T) { + router := NewRouter() + recorder := httptest.NewRecorder() + + req, err := http.NewRequest("GET", "http://localhost:3000/foo", nil) + if err != nil { + t.Error(err) + } + context := New().createContext(recorder, req) + + result := "" + + f1 := func() { + result += "foo" + } + + f2 := func(c Context) { + result += "bar" + c.Next() + result += "bing" + } + + f3 := func() string { + result += "bat" + return "Hello world" + } + + f4 := func() { + result += "baz" + } + + router.Get("/foo", f1, f2, f3, f4) + + router.Handle(recorder, req, context) + expect(t, result, "foobarbatbing") + expect(t, recorder.Body.String(), "Hello world") +} + +var routeTests = []struct { + // in + method string + path string + + // out + ok bool + params map[string]string +}{ + {"GET", "/foo/123/bat/321", true, map[string]string{"bar": "123", "baz": "321"}}, + {"POST", "/foo/123/bat/321", false, map[string]string{}}, + {"GET", "/foo/hello/bat/world", true, map[string]string{"bar": "hello", "baz": "world"}}, + {"GET", "foo/hello/bat/world", false, map[string]string{}}, + {"GET", "/foo/123/bat/321/", true, map[string]string{"bar": "123", "baz": "321"}}, + {"GET", "/foo/123/bat/321//", false, map[string]string{}}, + {"GET", "/foo/123//bat/321/", false, map[string]string{}}, +} + +func Test_RouteMatching(t *testing.T) { + route := newRoute("GET", "/foo/:bar/bat/:baz", nil) + for _, tt := range routeTests { + ok, params := route.Match(tt.method, tt.path) + if ok != tt.ok || params["bar"] != tt.params["bar"] || params["baz"] != tt.params["baz"] { + t.Errorf("expected: (%v, %v) got: (%v, %v)", tt.ok, tt.params, ok, params) + } + } +} + +func Test_NotFound(t *testing.T) { + router := NewRouter() + recorder := httptest.NewRecorder() + + req, _ := http.NewRequest("GET", "http://localhost:3000/foo", nil) + context := New().createContext(recorder, req) + + router.NotFound(func(res http.ResponseWriter) { + http.Error(res, "Nope", http.StatusNotFound) + }) + + router.Handle(recorder, req, context) + expect(t, recorder.Code, http.StatusNotFound) + expect(t, recorder.Body.String(), "Nope\n") +} + +func Test_Any(t *testing.T) { + router := NewRouter() + router.Any("/foo", func(res http.ResponseWriter) { + http.Error(res, "Nope", http.StatusNotFound) + }) + + recorder := httptest.NewRecorder() + req, _ := http.NewRequest("GET", "http://localhost:3000/foo", nil) + context := New().createContext(recorder, req) + router.Handle(recorder, req, context) + + expect(t, recorder.Code, http.StatusNotFound) + expect(t, recorder.Body.String(), "Nope\n") + + recorder = httptest.NewRecorder() + req, _ = http.NewRequest("PUT", "http://localhost:3000/foo", nil) + context = New().createContext(recorder, req) + router.Handle(recorder, req, context) + + expect(t, recorder.Code, http.StatusNotFound) + expect(t, recorder.Body.String(), "Nope\n") +} + +func Test_URLFor(t *testing.T) { + router := NewRouter() + var barIDNameRoute, fooRoute, barRoute Route + + fooRoute = router.Get("/foo", func() { + // Nothing + }) + + barRoute = router.Post("/bar/:id", func(params Params) { + // Nothing + }) + + barIDNameRoute = router.Get("/bar/:id/:name", func(params Params, routes Routes) { + expect(t, routes.URLFor(fooRoute, nil), "/foo") + expect(t, routes.URLFor(barRoute, 5), "/bar/5") + expect(t, routes.URLFor(barIDNameRoute, 5, "john"), "/bar/5/john") + }) + + // code should be 200 if none is returned from the handler + recorder := httptest.NewRecorder() + req, err := http.NewRequest("GET", "http://localhost:3000/bar/foo/bar", nil) + if err != nil { + t.Error(err) + } + context := New().createContext(recorder, req) + router.Handle(recorder, req, context) +} diff --git a/Godeps/_workspace/src/github.com/codegangsta/martini/static.go b/Godeps/_workspace/src/github.com/codegangsta/martini/static.go new file mode 100644 index 000000000..747036817 --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/martini/static.go @@ -0,0 +1,52 @@ +package martini + +import ( + "log" + "net/http" + "path" + "strings" +) + +// Static returns a middleware handler that serves static files in the given directory. +func Static(directory string) Handler { + dir := http.Dir(directory) + return func(res http.ResponseWriter, req *http.Request, log *log.Logger) { + file := req.URL.Path + f, err := dir.Open(file) + if err != nil { + // discard the error? + return + } + defer f.Close() + + fi, err := f.Stat() + if err != nil { + return + } + + // Try to serve index.html + if fi.IsDir() { + + // redirect if missing trailing slash + if !strings.HasSuffix(file, "/") { + http.Redirect(res, req, file+"/", http.StatusFound) + return + } + + file = path.Join(file, "index.html") + f, err = dir.Open(file) + if err != nil { + return + } + defer f.Close() + + fi, err = f.Stat() + if err != nil || fi.IsDir() { + return + } + } + + log.Println("[Static] Serving " + file) + http.ServeContent(res, req, file, fi.ModTime(), f) + } +} diff --git a/build.sh b/build.sh index af31c4ac1..8bf588fc9 100755 --- a/build.sh +++ b/build.sh @@ -6,12 +6,19 @@ distFiles=(README.md LICENSE) # apart from the binary itself version=$(git describe --always) build() { - go build -ldflags "-w -X main.Version $version" ./cmd/syncthing + if which -s godep ; then + godep=godep + else + echo "Warning: no godep, using \"go get\" instead." + echo "Try \"go get github.com/tools/godep\"." + go get -d ./cmd/syncthing + godep= + fi + ${godep} go build -ldflags "-w -X main.Version $version" ./cmd/syncthing } prepare() { go run cmd/assets/assets.go gui > auto/gui.files.go - go get -d } test() { @@ -43,6 +50,10 @@ case "$1" in build ;; + test) + test + ;; + tar) rm -f *.tar.gz *.zip prepare