diff --git a/contrib/backends/nntpchand/Makefile b/contrib/backends/nntpchand/Makefile new file mode 100644 index 0000000..a97af84 --- /dev/null +++ b/contrib/backends/nntpchand/Makefile @@ -0,0 +1,11 @@ +REPO=$(shell dirname $(realpath $(lastword $(MAKEFILE_LIST)))) + +all: clean build + +build: nntpchand + +nntpchand: + GOPATH=$(REPO) go build -v + +clean: + GOPATH=$(REPO) go clean -v diff --git a/contrib/backends/nntpchand/main.go b/contrib/backends/nntpchand/main.go new file mode 100644 index 0000000..d0d58d6 --- /dev/null +++ b/contrib/backends/nntpchand/main.go @@ -0,0 +1,9 @@ +package main + +import ( + "nntpchan/cmd/nntpchan" +) + +func main() { + nntpchan.Main() +} diff --git a/contrib/backends/nntpchand/src/nntpchan/cmd/nntpchan/main.go b/contrib/backends/nntpchand/src/nntpchan/cmd/nntpchan/main.go new file mode 100644 index 0000000..adabeff --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/cmd/nntpchan/main.go @@ -0,0 +1,160 @@ +package nntpchan + +import ( + log "github.com/Sirupsen/logrus" + "net" + _ "net/http/pprof" + "nntpchan/lib/config" + "nntpchan/lib/database" + "nntpchan/lib/frontend" + "nntpchan/lib/nntp" + "nntpchan/lib/store" + "nntpchan/lib/webhooks" + "os" + "os/signal" + "syscall" + "time" +) + +type runStatus struct { + nntpListener net.Listener + run bool + done chan error +} + +func (st *runStatus) Stop() { + st.run = false + if st.nntpListener != nil { + st.nntpListener.Close() + } + st.nntpListener = nil + log.Info("stopping daemon process") +} + +func Main() { + st := &runStatus{ + run: true, + done: make(chan error), + } + log.Info("starting up nntpchan...") + cfgFname := "nntpchan.json" + conf, err := config.Ensure(cfgFname) + if err != nil { + log.Fatal(err) + } + + if conf.Log == "debug" { + log.SetLevel(log.DebugLevel) + } + + sconfig := conf.Store + + if sconfig == nil { + log.Fatal("no article storage configured") + } + + nconfig := conf.NNTP + + if nconfig == nil { + log.Fatal("no nntp server configured") + } + + dconfig := conf.Database + + if dconfig == nil { + log.Fatal("no database configured") + } + + // create nntp server + nserv := nntp.NewServer() + nserv.Config = nconfig + nserv.Feeds = conf.Feeds + + if nconfig.LoginsFile != "" { + nserv.Auth = nntp.FlatfileAuth(nconfig.LoginsFile) + } + + // create article storage + nserv.Storage, err = store.NewFilesytemStorage(sconfig.Path, true) + if err != nil { + log.Fatal(err) + } + + if conf.WebHooks != nil && len(conf.WebHooks) > 0 { + // put webhooks into nntp server event hooks + nserv.Hooks = webhooks.NewWebhooks(conf.WebHooks, nserv.Storage) + } + + if conf.NNTPHooks != nil && len(conf.NNTPHooks) > 0 { + var hooks nntp.MulitHook + if nserv.Hooks != nil { + hooks = append(hooks, nserv.Hooks) + } + for _, h := range conf.NNTPHooks { + hooks = append(hooks, nntp.NewHook(h)) + } + nserv.Hooks = hooks + } + + var db database.Database + for _, fconf := range conf.Frontends { + var f frontend.Frontend + f, err = frontend.NewHTTPFrontend(fconf, db) + if err == nil { + go f.Serve() + } + } + + // start persisting feeds + go nserv.PersistFeeds() + + // handle signals + sigchnl := make(chan os.Signal, 1) + signal.Notify(sigchnl, syscall.SIGHUP, os.Interrupt) + go func() { + for { + s := <-sigchnl + if s == syscall.SIGHUP { + // handle SIGHUP + conf, err := config.Ensure(cfgFname) + if err == nil { + log.Infof("reloading config: %s", cfgFname) + nserv.ReloadServer(conf.NNTP) + nserv.ReloadFeeds(conf.Feeds) + } else { + log.Errorf("failed to reload config: %s", err) + } + } else if s == os.Interrupt { + // handle interrupted, clean close + st.Stop() + return + } + } + }() + go func() { + var err error + for st.run { + var nl net.Listener + naddr := conf.NNTP.Bind + log.Infof("Bind nntp server to %s", naddr) + nl, err = net.Listen("tcp", naddr) + if err == nil { + st.nntpListener = nl + err = nserv.Serve(nl) + if err != nil { + nl.Close() + log.Errorf("nntpserver.serve() %s", err.Error()) + } + } else { + log.Errorf("nntp server net.Listen failed: %s", err.Error()) + } + time.Sleep(time.Second) + } + st.done <- err + }() + e := <-st.done + if e != nil { + log.Fatal(e) + } + log.Info("ended") +} diff --git a/contrib/backends/nntpchand/src/nntpchan/cmd/nntpserver/main.go b/contrib/backends/nntpchand/src/nntpchan/cmd/nntpserver/main.go new file mode 100644 index 0000000..bab2d8e --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/cmd/nntpserver/main.go @@ -0,0 +1,42 @@ +package main + +// simple nntp server + +import ( + log "github.com/Sirupsen/logrus" + "github.com/majestrate/srndv2/lib/config" + "github.com/majestrate/srndv2/lib/nntp" + "github.com/majestrate/srndv2/lib/store" + "net" +) + +func main() { + + log.Info("starting NNTP server...") + conf, err := config.Ensure("settings.json") + if err != nil { + log.Fatal(err) + } + + if conf.Log == "debug" { + log.SetLevel(log.DebugLevel) + } + + serv := &nntp.Server{ + Config: conf.NNTP, + Feeds: conf.Feeds, + } + serv.Storage, err = store.NewFilesytemStorage(conf.Store.Path, false) + if err != nil { + log.Fatal(err) + } + l, err := net.Listen("tcp", conf.NNTP.Bind) + if err != nil { + log.Fatal(err) + } + log.Info("listening on ", l.Addr()) + err = serv.Serve(l) + if err != nil { + log.Fatal(err) + } +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/admin/doc.go b/contrib/backends/nntpchand/src/nntpchan/lib/admin/doc.go new file mode 100644 index 0000000..372f1f3 --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/admin/doc.go @@ -0,0 +1,4 @@ +// +// server admin panel +// +package admin diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/admin/server.go b/contrib/backends/nntpchand/src/nntpchan/lib/admin/server.go new file mode 100644 index 0000000..0f6611b --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/admin/server.go @@ -0,0 +1,16 @@ +package admin + +import ( + "net/http" +) + +type Server struct { +} + +func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { + +} + +func NewServer() *Server { + return &Server{} +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/api/api.go b/contrib/backends/nntpchand/src/nntpchan/lib/api/api.go new file mode 100644 index 0000000..caf1e6a --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/api/api.go @@ -0,0 +1,10 @@ +package api + +import ( + "nntpchan/lib/model" +) + +// json api +type API interface { + MakePost(p model.Post) +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/api/doc.go b/contrib/backends/nntpchand/src/nntpchan/lib/api/doc.go new file mode 100644 index 0000000..c2402fc --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/api/doc.go @@ -0,0 +1,2 @@ +// json api +package api diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/api/server.go b/contrib/backends/nntpchand/src/nntpchan/lib/api/server.go new file mode 100644 index 0000000..6db4efa --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/api/server.go @@ -0,0 +1,20 @@ +package api + +import ( + "github.com/gorilla/mux" + "net/http" +) + +// api server +type Server struct { +} + +func (s *Server) HandlePing(w http.ResponseWriter, r *http.Request) { + +} + +// inject api routes +func (s *Server) SetupRoutes(r *mux.Router) { + // setup api pinger + r.Path("/ping").HandlerFunc(s.HandlePing) +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/config/article.go b/contrib/backends/nntpchand/src/nntpchan/lib/config/article.go new file mode 100644 index 0000000..1c8e8d1 --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/config/article.go @@ -0,0 +1,73 @@ +package config + +import "regexp" + +// configration for local article policies +type ArticleConfig struct { + // explicitly allow these newsgroups (regexp) + AllowGroups []string `json:"whitelist"` + // explicitly disallow these newsgroups (regexp) + DisallowGroups []string `json:"blacklist"` + // only allow explicitly allowed groups + ForceWhitelist bool `json:"force-whitelist"` + // allow anonymous posts? + AllowAnon bool `json:"anon"` + // allow attachments? + AllowAttachments bool `json:"attachments"` + // allow anonymous attachments? + AllowAnonAttachments bool `json:"anon-attachments"` +} + +func (c *ArticleConfig) AllowGroup(group string) bool { + + for _, g := range c.DisallowGroups { + r := regexp.MustCompile(g) + if r.MatchString(group) && c.ForceWhitelist { + // disallowed + return false + } + } + + // check allowed groups first + for _, g := range c.AllowGroups { + r := regexp.MustCompile(g) + if r.MatchString(g) { + return true + } + } + + return !c.ForceWhitelist +} + +// allow an article? +func (c *ArticleConfig) Allow(msgid, group string, anon, attachment bool) bool { + + // check attachment policy + if c.AllowGroup(group) { + allow := true + // no anon ? + if anon && !c.AllowAnon { + allow = false + } + // no attachments ? + if allow && attachment && !c.AllowAttachments { + allow = false + } + // no anon attachments ? + if allow && attachment && anon && !c.AllowAnonAttachments { + allow = false + } + return allow + } else { + return false + } +} + +var DefaultArticlePolicy = ArticleConfig{ + AllowGroups: []string{"ctl", "overchan.test"}, + DisallowGroups: []string{"overchan.cp"}, + ForceWhitelist: false, + AllowAnon: true, + AllowAttachments: true, + AllowAnonAttachments: false, +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/config/cache.go b/contrib/backends/nntpchand/src/nntpchan/lib/config/cache.go new file mode 100644 index 0000000..b6b1312 --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/config/cache.go @@ -0,0 +1,13 @@ +package config + +// caching interface configuration +type CacheConfig struct { + // backend cache driver name + Backend string `json:"backend"` + // address for cache + Addr string `json:"addr"` + // username for login + User string `json:"user"` + // password for login + Password string `json:"password"` +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/config/config.go b/contrib/backends/nntpchand/src/nntpchan/lib/config/config.go new file mode 100644 index 0000000..b7c2bbe --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/config/config.go @@ -0,0 +1,87 @@ +package config + +import ( + "bytes" + "encoding/json" + "io/ioutil" + "os" +) + +// main configuration +type Config struct { + // nntp server configuration + NNTP *NNTPServerConfig `json:"nntp"` + // log level + Log string `json:"log"` + // article storage config + Store *StoreConfig `json:"storage"` + // web hooks to call + WebHooks []*WebhookConfig `json:"webhooks"` + // external scripts to call + NNTPHooks []*NNTPHookConfig `json:"nntphooks"` + // database backend configuration + Database *DatabaseConfig `json:"db"` + // list of feeds to add on runtime + Feeds []*FeedConfig `json:"feeds"` + // frontend config + Frontends []*FrontendConfig `json:"frontends"` + // unexported fields ... + + // absolute filepath to configuration + fpath string +} + +// default configuration +var DefaultConfig = Config{ + Store: &DefaultStoreConfig, + NNTP: &DefaultNNTPConfig, + Database: &DefaultDatabaseConfig, + WebHooks: []*WebhookConfig{DefaultWebHookConfig}, + NNTPHooks: []*NNTPHookConfig{DefaultNNTPHookConfig}, + Feeds: DefaultFeeds, + Frontends: []*FrontendConfig{&DefaultFrontendConfig}, + Log: "debug", +} + +// reload configuration +func (c *Config) Reload() (err error) { + var b []byte + b, err = ioutil.ReadFile(c.fpath) + if err == nil { + err = json.Unmarshal(b, c) + } + return +} + +// ensure that a config file exists +// creates one if it does not exist +func Ensure(fname string) (cfg *Config, err error) { + _, err = os.Stat(fname) + if os.IsNotExist(err) { + err = nil + var d []byte + d, err = json.Marshal(&DefaultConfig) + if err == nil { + b := new(bytes.Buffer) + err = json.Indent(b, d, "", " ") + if err == nil { + err = ioutil.WriteFile(fname, b.Bytes(), 0600) + } + } + } + if err == nil { + cfg, err = Load(fname) + } + return +} + +// load configuration file +func Load(fname string) (cfg *Config, err error) { + cfg = new(Config) + cfg.fpath = fname + err = cfg.Reload() + if err != nil { + cfg = nil + } + return +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/config/database.go b/contrib/backends/nntpchand/src/nntpchan/lib/config/database.go new file mode 100644 index 0000000..6fe92c5 --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/config/database.go @@ -0,0 +1,18 @@ +package config + +type DatabaseConfig struct { + // url or address for database connector + Addr string `json:"addr"` + // password to use + Password string `json:"password"` + // username to use + Username string `json:"username"` + // type of database to use + Type string `json:"type"` +} + +var DefaultDatabaseConfig = DatabaseConfig{ + Type: "postgres", + Addr: "/var/run/postgresql", + Password: "", +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/config/doc.go b/contrib/backends/nntpchand/src/nntpchan/lib/config/doc.go new file mode 100644 index 0000000..db5c659 --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/config/doc.go @@ -0,0 +1,4 @@ +// +// package for parsing config files +// +package config diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/config/feed.go b/contrib/backends/nntpchand/src/nntpchan/lib/config/feed.go new file mode 100644 index 0000000..6ae4bfa --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/config/feed.go @@ -0,0 +1,33 @@ +package config + +// configuration for 1 nntp feed +type FeedConfig struct { + // feed's policy, filters articles + Policy *ArticleConfig `json:"policy"` + // remote server's address + Addr string `json:"addr"` + // proxy server config + Proxy *ProxyConfig `json:"proxy"` + // nntp username to log in with + Username string `json:"username"` + // nntp password to use when logging in + Password string `json:"password"` + // do we want to use tls? + TLS bool `json:"tls"` + // the name of this feed + Name string `json:"name"` + // how often to pull articles from the server in minutes + // 0 for never + PullInterval int `json:"pull"` +} + +var DuummyFeed = FeedConfig{ + Policy: &DefaultArticlePolicy, + Addr: "nntp.dummy.tld:1119", + Proxy: &DefaultTorProxy, + Name: "dummy", +} + +var DefaultFeeds = []*FeedConfig{ + &DuummyFeed, +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/config/frontend.go b/contrib/backends/nntpchand/src/nntpchan/lib/config/frontend.go new file mode 100644 index 0000000..d100656 --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/config/frontend.go @@ -0,0 +1,21 @@ +package config + +type FrontendConfig struct { + // bind to address + BindAddr string `json:"bind"` + // frontend cache + Cache *CacheConfig `json:"cache"` + // frontend ssl settings + SSL *SSLSettings `json:"ssl"` + // static files directory + Static string `json:"static_dir"` + // http middleware configuration + Middleware *MiddlewareConfig `json:"middleware"` +} + +// default Frontend Configuration +var DefaultFrontendConfig = FrontendConfig{ + BindAddr: "127.0.0.1:18888", + Static: "./files/static/", + Middleware: &DefaultMiddlewareConfig, +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/config/hook.go b/contrib/backends/nntpchand/src/nntpchan/lib/config/hook.go new file mode 100644 index 0000000..81200ca --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/config/hook.go @@ -0,0 +1,15 @@ +package config + +// config for external callback for nntp articles +type NNTPHookConfig struct { + // name of hook + Name string `json:"name"` + // executable script path to be called with arguments: /path/to/article + Exec string `json:"exec"` +} + +// default dummy hook +var DefaultNNTPHookConfig = &NNTPHookConfig{ + Name: "dummy", + Exec: "/bin/true", +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/config/middleware.go b/contrib/backends/nntpchand/src/nntpchan/lib/config/middleware.go new file mode 100644 index 0000000..413bf2a --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/config/middleware.go @@ -0,0 +1,14 @@ +package config + +// configuration for http middleware +type MiddlewareConfig struct { + // middleware type, currently just 1 is available: overchan + Type string `json:"type"` + // directory for our html templates + Templates string `json:"templates_dir"` +} + +var DefaultMiddlewareConfig = MiddlewareConfig{ + Type: "overchan", + Templates: "./files/templates/overchan/", +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/config/nntp.go b/contrib/backends/nntpchand/src/nntpchan/lib/config/nntp.go new file mode 100644 index 0000000..a3d4f25 --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/config/nntp.go @@ -0,0 +1,24 @@ +package config + +type NNTPServerConfig struct { + // address to bind to + Bind string `json:"bind"` + // name of the nntp server + Name string `json:"name"` + // default inbound article policy + Article *ArticleConfig `json:"policy"` + // do we allow anonymous NNTP sync? + AnonNNTP bool `json:"anon-nntp"` + // ssl settings for nntp + SSL *SSLSettings + // file with login credentials + LoginsFile string `json:"authfile"` +} + +var DefaultNNTPConfig = NNTPServerConfig{ + AnonNNTP: false, + Bind: "0.0.0.0:1119", + Name: "nntp.server.tld", + Article: &DefaultArticlePolicy, + LoginsFile: "", +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/config/proxy.go b/contrib/backends/nntpchand/src/nntpchan/lib/config/proxy.go new file mode 100644 index 0000000..7ed7003 --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/config/proxy.go @@ -0,0 +1,13 @@ +package config + +// proxy configuration +type ProxyConfig struct { + Type string `json:"type"` + Addr string `json:"addr"` +} + +// default tor proxy +var DefaultTorProxy = ProxyConfig{ + Type: "socks", + Addr: "127.0.0.1:9050", +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/config/ssl.go b/contrib/backends/nntpchand/src/nntpchan/lib/config/ssl.go new file mode 100644 index 0000000..1e45ed4 --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/config/ssl.go @@ -0,0 +1,11 @@ +package config + +// settings for setting up ssl +type SSLSettings struct { + // path to ssl private key + SSLKeyFile string `json:"key"` + // path to ssl certificate signed by CA + SSLCertFile string `json:"cert"` + // domain name to use for ssl + DomainName string `json:"fqdn"` +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/config/store.go b/contrib/backends/nntpchand/src/nntpchan/lib/config/store.go new file mode 100644 index 0000000..31abf86 --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/config/store.go @@ -0,0 +1,10 @@ +package config + +type StoreConfig struct { + // path to article directory + Path string `json:"path"` +} + +var DefaultStoreConfig = StoreConfig{ + Path: "storage", +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/config/webhooks.go b/contrib/backends/nntpchand/src/nntpchan/lib/config/webhooks.go new file mode 100644 index 0000000..9c7b266 --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/config/webhooks.go @@ -0,0 +1,17 @@ +package config + +// configuration for a single web hook +type WebhookConfig struct { + // user provided name for this hook + Name string `json:"name"` + // callback URL for webhook + URL string `json:"url"` + // dialect to use when calling webhook + Dialect string `json:"dialect"` +} + +var DefaultWebHookConfig = &WebhookConfig{ + Name: "vichan", + Dialect: "vichan", + URL: "http://localhost/webhook.php", +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/crypto/doc.go b/contrib/backends/nntpchand/src/nntpchan/lib/crypto/doc.go new file mode 100644 index 0000000..a912506 --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/crypto/doc.go @@ -0,0 +1,5 @@ +// +// nntpchan crypto package +// wraps all external crypro libs +// +package crypto diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/crypto/hash.go b/contrib/backends/nntpchand/src/nntpchan/lib/crypto/hash.go new file mode 100644 index 0000000..f0bea5b --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/crypto/hash.go @@ -0,0 +1,8 @@ +package crypto + +import ( + "github.com/dchest/blake256" +) + +// common hash function is blake2 +var Hash = blake256.New diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/crypto/nacl.go b/contrib/backends/nntpchand/src/nntpchan/lib/crypto/nacl.go new file mode 100644 index 0000000..140565b --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/crypto/nacl.go @@ -0,0 +1,82 @@ +package crypto + +import ( + "crypto/sha512" + "hash" + "nntpchan/lib/crypto/nacl" +) + +type fuckyNacl struct { + k []byte + hash hash.Hash +} + +func (fucky *fuckyNacl) Write(d []byte) (int, error) { + return fucky.hash.Write(d) +} + +func (fucky *fuckyNacl) Sign() (s Signature) { + h := fucky.hash.Sum(nil) + if h == nil { + panic("fuck.hash.Sum == nil") + } + kp := nacl.LoadSignKey(fucky.k) + defer kp.Free() + sk := kp.Secret() + sig := nacl.CryptoSignFucky(h, sk) + if sig == nil { + panic("fucky signer's call to nacl.CryptoSignFucky returned nil") + } + s = Signature(sig) + fucky.resetState() + return +} + +// reset inner state so we can reuse this fuckyNacl for another operation +func (fucky *fuckyNacl) resetState() { + fucky.hash = sha512.New() +} + +func (fucky *fuckyNacl) Verify(sig Signature) (valid bool) { + h := fucky.hash.Sum(nil) + if h == nil { + panic("fuck.hash.Sum == nil") + } + valid = nacl.CryptoVerifyFucky(h, sig, fucky.k) + fucky.resetState() + return +} + +func createFucky(k []byte) *fuckyNacl { + return &fuckyNacl{ + k: k, + hash: sha512.New(), + } +} + +// create a standard signer given a secret key +func CreateSigner(sk []byte) Signer { + return createFucky(sk) +} + +// create a standard verifier given a public key +func CreateVerifier(pk []byte) Verifer { + return createFucky(pk) +} + +// get the public component given the secret key +func ToPublic(sk []byte) (pk []byte) { + kp := nacl.LoadSignKey(sk) + defer kp.Free() + pk = kp.Public() + return +} + +// create a standard keypair +func GenKeypair() (pk, sk []byte) { + kp := nacl.GenSignKeypair() + defer kp.Free() + pk = kp.Public() + sk = kp.Seed() + return +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/crypto/nacl/box.go b/contrib/backends/nntpchand/src/nntpchan/lib/crypto/nacl/box.go new file mode 100644 index 0000000..cf07a9a --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/crypto/nacl/box.go @@ -0,0 +1,95 @@ +package nacl + +// #cgo freebsd CFLAGS: -I/usr/local/include +// #cgo freebsd LDFLAGS: -L/usr/local/lib +// #cgo LDFLAGS: -lsodium +// #include +import "C" + +import ( + "errors" +) + +// encrypts a message to a user given their public key is known +// returns an encrypted box +func CryptoBox(msg, nounce, pk, sk []byte) ([]byte, error) { + msgbuff := NewBuffer(msg) + defer msgbuff.Free() + + // check sizes + if len(pk) != int(C.crypto_box_publickeybytes()) { + err := errors.New("len(pk) != crypto_box_publickey_bytes") + return nil, err + } + if len(sk) != int(C.crypto_box_secretkeybytes()) { + err := errors.New("len(sk) != crypto_box_secretkey_bytes") + return nil, err + } + if len(nounce) != int(C.crypto_box_macbytes()) { + err := errors.New("len(nounce) != crypto_box_macbytes()") + return nil, err + } + + pkbuff := NewBuffer(pk) + defer pkbuff.Free() + skbuff := NewBuffer(sk) + defer skbuff.Free() + nouncebuff := NewBuffer(nounce) + defer nouncebuff.Free() + + resultbuff := malloc(msgbuff.size + nouncebuff.size) + defer resultbuff.Free() + res := C.crypto_box_easy(resultbuff.uchar(), msgbuff.uchar(), C.ulonglong(msgbuff.size), nouncebuff.uchar(), pkbuff.uchar(), skbuff.uchar()) + if res != 0 { + err := errors.New("crypto_box_easy failed") + return nil, err + } + return resultbuff.Bytes(), nil +} + +// open an encrypted box +func CryptoBoxOpen(box, nounce, sk, pk []byte) ([]byte, error) { + boxbuff := NewBuffer(box) + defer boxbuff.Free() + + // check sizes + if len(pk) != int(C.crypto_box_publickeybytes()) { + err := errors.New("len(pk) != crypto_box_publickey_bytes") + return nil, err + } + if len(sk) != int(C.crypto_box_secretkeybytes()) { + err := errors.New("len(sk) != crypto_box_secretkey_bytes") + return nil, err + } + if len(nounce) != int(C.crypto_box_macbytes()) { + err := errors.New("len(nounce) != crypto_box_macbytes()") + return nil, err + } + + pkbuff := NewBuffer(pk) + defer pkbuff.Free() + skbuff := NewBuffer(sk) + defer skbuff.Free() + nouncebuff := NewBuffer(nounce) + defer nouncebuff.Free() + resultbuff := malloc(boxbuff.size - nouncebuff.size) + defer resultbuff.Free() + + // decrypt + res := C.crypto_box_open_easy(resultbuff.uchar(), boxbuff.uchar(), C.ulonglong(boxbuff.size), nouncebuff.uchar(), pkbuff.uchar(), skbuff.uchar()) + if res != 0 { + return nil, errors.New("crypto_box_open_easy failed") + } + // return result + return resultbuff.Bytes(), nil +} + +// generate a new nounce +func NewBoxNounce() []byte { + return RandBytes(NounceLen()) +} + +// length of a nounce +func NounceLen() int { + return int(C.crypto_box_macbytes()) +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/crypto/nacl/buffer.go b/contrib/backends/nntpchand/src/nntpchan/lib/crypto/nacl/buffer.go new file mode 100644 index 0000000..64b0a1c --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/crypto/nacl/buffer.go @@ -0,0 +1,86 @@ +package nacl + +// #cgo freebsd CFLAGS: -I/usr/local/include +// #cgo freebsd LDFLAGS: -L/usr/local/lib +// #cgo LDFLAGS: -lsodium +// #include +// +// unsigned char * deref_uchar(void * ptr) { return (unsigned char*) ptr; } +// +import "C" + +import ( + "encoding/hex" + "reflect" + "unsafe" +) + +// wrapper arround malloc/free +type Buffer struct { + ptr unsafe.Pointer + length C.int + size C.size_t +} + +// wrapper arround nacl.malloc +func Malloc(size int) *Buffer { + if size > 0 { + return malloc(C.size_t(size)) + } + return nil +} + +// does not check for negatives +func malloc(size C.size_t) *Buffer { + ptr := C.malloc(size) + C.sodium_memzero(ptr, size) + buffer := &Buffer{ptr: ptr, size: size, length: C.int(size)} + return buffer +} + +// create a new buffer copying from a byteslice +func NewBuffer(buff []byte) *Buffer { + buffer := Malloc(len(buff)) + if buffer == nil { + return nil + } + if copy(buffer.Data(), buff) != len(buff) { + return nil + } + return buffer +} + +func (self *Buffer) uchar() *C.uchar { + return C.deref_uchar(self.ptr) +} + +func (self *Buffer) Length() int { + return int(self.length) +} + +// get immutable byte slice +func (self *Buffer) Bytes() []byte { + buff := make([]byte, self.Length()) + copy(buff, self.Data()) + return buff +} + +// get underlying byte slice +func (self *Buffer) Data() []byte { + hdr := reflect.SliceHeader{ + Data: uintptr(self.ptr), + Len: self.Length(), + Cap: self.Length(), + } + return *(*[]byte)(unsafe.Pointer(&hdr)) +} + +func (self *Buffer) String() string { + return hex.EncodeToString(self.Data()) +} + +// zero out memory and then free +func (self *Buffer) Free() { + C.sodium_memzero(self.ptr, self.size) + C.free(self.ptr) +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/crypto/nacl/key.go b/contrib/backends/nntpchand/src/nntpchan/lib/crypto/nacl/key.go new file mode 100644 index 0000000..6c03265 --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/crypto/nacl/key.go @@ -0,0 +1,178 @@ +package nacl + +// #cgo freebsd CFLAGS: -I/usr/local/include +// #cgo freebsd LDFLAGS: -L/usr/local/lib +// #cgo LDFLAGS: -lsodium +// #include +import "C" + +import ( + "encoding/hex" + "errors" + "fmt" +) + +type KeyPair struct { + pk *Buffer + sk *Buffer +} + +// free this keypair from memory +func (self *KeyPair) Free() { + self.pk.Free() + self.sk.Free() +} + +func (self *KeyPair) Secret() []byte { + return self.sk.Bytes() +} + +func (self *KeyPair) Public() []byte { + return self.pk.Bytes() +} + +func (self *KeyPair) Seed() []byte { + seed_len := C.crypto_sign_seedbytes() + return self.sk.Bytes()[:seed_len] +} + +// generate a keypair +func GenSignKeypair() *KeyPair { + sk_len := C.crypto_sign_secretkeybytes() + sk := malloc(sk_len) + pk_len := C.crypto_sign_publickeybytes() + pk := malloc(pk_len) + res := C.crypto_sign_keypair(pk.uchar(), sk.uchar()) + if res == 0 { + return &KeyPair{pk, sk} + } + pk.Free() + sk.Free() + return nil +} + +// get public key from secret key +func GetSignPubkey(sk []byte) ([]byte, error) { + sk_len := C.crypto_sign_secretkeybytes() + if C.size_t(len(sk)) != sk_len { + return nil, errors.New(fmt.Sprintf("nacl.GetSignPubkey() invalid secret key size %d != %d", len(sk), sk_len)) + } + + pk_len := C.crypto_sign_publickeybytes() + pkbuff := malloc(pk_len) + defer pkbuff.Free() + + skbuff := NewBuffer(sk) + defer skbuff.Free() + //XXX: hack + res := C.crypto_sign_seed_keypair(pkbuff.uchar(), skbuff.uchar(), skbuff.uchar()) + + if res != 0 { + return nil, errors.New(fmt.Sprintf("nacl.GetSignPubkey() failed to get public key from secret key: %d", res)) + } + + return pkbuff.Bytes(), nil +} + +// make keypair from seed +func LoadSignKey(seed []byte) *KeyPair { + seed_len := C.crypto_sign_seedbytes() + if C.size_t(len(seed)) != seed_len { + return nil + } + seedbuff := NewBuffer(seed) + defer seedbuff.Free() + pk_len := C.crypto_sign_publickeybytes() + sk_len := C.crypto_sign_secretkeybytes() + pkbuff := malloc(pk_len) + skbuff := malloc(sk_len) + res := C.crypto_sign_seed_keypair(pkbuff.uchar(), skbuff.uchar(), seedbuff.uchar()) + if res != 0 { + pkbuff.Free() + skbuff.Free() + return nil + } + return &KeyPair{pkbuff, skbuff} +} + +func GenBoxKeypair() *KeyPair { + sk_len := C.crypto_box_secretkeybytes() + sk := malloc(sk_len) + pk_len := C.crypto_box_publickeybytes() + pk := malloc(pk_len) + res := C.crypto_box_keypair(pk.uchar(), sk.uchar()) + if res == 0 { + return &KeyPair{pk, sk} + } + pk.Free() + sk.Free() + return nil +} + +// get public key from secret key +func GetBoxPubkey(sk []byte) []byte { + sk_len := C.crypto_box_seedbytes() + if C.size_t(len(sk)) != sk_len { + return nil + } + + pk_len := C.crypto_box_publickeybytes() + pkbuff := malloc(pk_len) + defer pkbuff.Free() + + skbuff := NewBuffer(sk) + defer skbuff.Free() + + // compute the public key + C.crypto_scalarmult_base(pkbuff.uchar(), skbuff.uchar()) + + return pkbuff.Bytes() +} + +// load keypair from secret key +func LoadBoxKey(sk []byte) *KeyPair { + pk := GetBoxPubkey(sk) + if pk == nil { + return nil + } + pkbuff := NewBuffer(pk) + skbuff := NewBuffer(sk) + return &KeyPair{pkbuff, skbuff} +} + +// make keypair from seed +func SeedBoxKey(seed []byte) *KeyPair { + seed_len := C.crypto_box_seedbytes() + if C.size_t(len(seed)) != seed_len { + return nil + } + seedbuff := NewBuffer(seed) + defer seedbuff.Free() + pk_len := C.crypto_box_publickeybytes() + sk_len := C.crypto_box_secretkeybytes() + pkbuff := malloc(pk_len) + skbuff := malloc(sk_len) + res := C.crypto_box_seed_keypair(pkbuff.uchar(), skbuff.uchar(), seedbuff.uchar()) + if res != 0 { + pkbuff.Free() + skbuff.Free() + return nil + } + return &KeyPair{pkbuff, skbuff} +} + +func (self *KeyPair) String() string { + return fmt.Sprintf("pk=%s sk=%s", hex.EncodeToString(self.pk.Data()), hex.EncodeToString(self.sk.Data())) +} + +func CryptoSignPublicLen() int { + return int(C.crypto_sign_publickeybytes()) +} + +func CryptoSignSecretLen() int { + return int(C.crypto_sign_secretkeybytes()) +} + +func CryptoSignSeedLen() int { + return int(C.crypto_sign_seedbytes()) +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/crypto/nacl/nacl.go b/contrib/backends/nntpchand/src/nntpchan/lib/crypto/nacl/nacl.go new file mode 100644 index 0000000..ee50d18 --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/crypto/nacl/nacl.go @@ -0,0 +1,44 @@ +package nacl + +// #cgo freebsd CFLAGS: -I/usr/local/include +// #cgo freebsd LDFLAGS: -L/usr/local/lib +// #cgo LDFLAGS: -lsodium +// #include +import "C" + +import ( + "log" +) + +// return how many bytes overhead does CryptoBox have +func CryptoBoxOverhead() int { + return int(C.crypto_box_macbytes()) +} + +// size of crypto_box public keys +func CryptoBoxPubKeySize() int { + return int(C.crypto_box_publickeybytes()) +} + +// size of crypto_box private keys +func CryptoBoxPrivKeySize() int { + return int(C.crypto_box_secretkeybytes()) +} + +// size of crypto_sign public keys +func CryptoSignPubKeySize() int { + return int(C.crypto_sign_publickeybytes()) +} + +// size of crypto_sign private keys +func CryptoSignPrivKeySize() int { + return int(C.crypto_sign_secretkeybytes()) +} + +// initialize sodium +func init() { + status := C.sodium_init() + if status == -1 { + log.Fatalf("failed to initialize libsodium status=%d", status) + } +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/crypto/nacl/rand.go b/contrib/backends/nntpchand/src/nntpchan/lib/crypto/nacl/rand.go new file mode 100644 index 0000000..05e0884 --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/crypto/nacl/rand.go @@ -0,0 +1,24 @@ +package nacl + +// #cgo freebsd CFLAGS: -I/usr/local/include +// #cgo freebsd LDFLAGS: -L/usr/local/lib +// #cgo LDFLAGS: -lsodium +// #include +import "C" + +func randbytes(size C.size_t) *Buffer { + + buff := malloc(size) + C.randombytes_buf(buff.ptr, size) + return buff + +} + +func RandBytes(size int) []byte { + if size > 0 { + buff := randbytes(C.size_t(size)) + defer buff.Free() + return buff.Bytes() + } + return nil +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/crypto/nacl/sign.go b/contrib/backends/nntpchand/src/nntpchan/lib/crypto/nacl/sign.go new file mode 100644 index 0000000..f80ade6 --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/crypto/nacl/sign.go @@ -0,0 +1,58 @@ +package nacl + +// #cgo freebsd CFLAGS: -I/usr/local/include +// #cgo freebsd LDFLAGS: -L/usr/local/lib +// #cgo LDFLAGS: -lsodium +// #include +import "C" + +// sign data detached with secret key sk +func CryptoSignDetached(msg, sk []byte) []byte { + msgbuff := NewBuffer(msg) + defer msgbuff.Free() + skbuff := NewBuffer(sk) + defer skbuff.Free() + if skbuff.size != C.crypto_sign_bytes() { + return nil + } + + // allocate the signature buffer + sig := malloc(C.crypto_sign_bytes()) + defer sig.Free() + // compute signature + siglen := C.ulonglong(0) + res := C.crypto_sign_detached(sig.uchar(), &siglen, msgbuff.uchar(), C.ulonglong(msgbuff.size), skbuff.uchar()) + if res == 0 && siglen == C.ulonglong(C.crypto_sign_bytes()) { + // return copy of signature buffer + return sig.Bytes() + } + // failure to sign + return nil +} + +// sign data with secret key sk +// return detached sig +// this uses crypto_sign instead pf crypto_sign_detached +func CryptoSignFucky(msg, sk []byte) []byte { + msgbuff := NewBuffer(msg) + defer msgbuff.Free() + skbuff := NewBuffer(sk) + defer skbuff.Free() + if skbuff.size != C.crypto_sign_bytes() { + return nil + } + + // allocate the signed message buffer + sig := malloc(C.crypto_sign_bytes() + msgbuff.size) + defer sig.Free() + // compute signature + siglen := C.ulonglong(0) + res := C.crypto_sign(sig.uchar(), &siglen, msgbuff.uchar(), C.ulonglong(msgbuff.size), skbuff.uchar()) + if res == 0 { + // return copy of signature inside the signed message + offset := int(C.crypto_sign_bytes()) + return sig.Bytes()[:offset] + } + // failure to sign + return nil +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/crypto/nacl/stream.go b/contrib/backends/nntpchand/src/nntpchan/lib/crypto/nacl/stream.go new file mode 100644 index 0000000..af3b181 --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/crypto/nacl/stream.go @@ -0,0 +1,342 @@ +package nacl + +import ( + "bytes" + "errors" + "io" + "net" + "time" +) + +// TOY encrypted authenticated stream protocol like tls + +var BadHandshake = errors.New("Bad handshake") +var ShortWrite = errors.New("short write") +var ShortRead = errors.New("short read") +var Closed = errors.New("socket closed") + +// write boxes at 512 bytes at a time +const DefaultMTU = 512 + +// wrapper arround crypto_box +// provides an authenticated encrypted stream +// this is a TOY +type CryptoStream struct { + // underlying stream to write on + stream io.ReadWriteCloser + // secret key seed + key *KeyPair + // public key of who we expect on the other end + remote_pk []byte + tx_nonce []byte + rx_nonce []byte + // box size + mtu int +} + +func (cs *CryptoStream) Close() (err error) { + if cs.key != nil { + cs.key.Free() + cs.key = nil + } + return cs.stream.Close() +} + +// implements io.Writer +func (cs *CryptoStream) Write(data []byte) (n int, err error) { + // let's split it up + for n < len(data) && err == nil { + if n+cs.mtu < len(data) { + err = cs.writeSegment(data[n : n+cs.mtu]) + n += cs.mtu + } else { + err = cs.writeSegment(data[n:]) + if err == nil { + n = len(data) + } + } + } + return +} + +func (cs *CryptoStream) public() (p []byte) { + p = cs.key.Public() + return +} + +func (cs *CryptoStream) secret() (s []byte) { + s = cs.key.Secret() + return +} + +// read 1 segment +func (cs *CryptoStream) readSegment() (s []byte, err error) { + var stream_read int + var seg []byte + nl := NounceLen() + msg := make([]byte, cs.mtu+nl) + stream_read, err = cs.stream.Read(msg) + seg, err = CryptoBoxOpen(msg[:stream_read], cs.rx_nonce, cs.secret(), cs.remote_pk) + if err == nil { + copy(cs.rx_nonce, seg[:nl]) + s = seg[nl:] + } + return +} + +// write 1 segment encrypted +// update nounce +func (cs *CryptoStream) writeSegment(data []byte) (err error) { + var segment []byte + nl := NounceLen() + msg := make([]byte, len(data)+nl) + // generate next nounce + nextNounce := NewBoxNounce() + copy(msg, nextNounce) + copy(msg[nl:], data) + // encrypt segment with current nounce + segment, err = CryptoBox(data, cs.tx_nonce, cs.remote_pk, cs.secret()) + var n int + n, err = cs.stream.Write(segment) + if n != len(segment) { + // short write? + err = ShortWrite + return + } + // update nounce + copy(cs.tx_nonce, nextNounce) + return +} + +// implements io.Reader +func (cs *CryptoStream) Read(data []byte) (n int, err error) { + var seg []byte + seg, err = cs.readSegment() + if err == nil { + if len(seg) <= len(data) { + copy(data, seg) + n = len(seg) + } else { + // too big? + err = ShortRead + } + } + return +} + +// version 0 protocol magic +var protocol_magic = []byte("BENIS|00") + +// verify that a handshake is signed right and is in the correct format etc +func verifyHandshake(hs, pk []byte) (valid bool) { + ml := len(protocol_magic) + // valid handshake? + if bytes.Equal(hs[0:ml], protocol_magic) { + // check pk + pl := CryptoSignPublicLen() + nl := NounceLen() + if bytes.Equal(pk, hs[ml:ml+pl]) { + // check signature + msg := hs[0 : ml+pl+nl] + sig := hs[ml+pl+nl:] + valid = CryptoVerifyFucky(msg, sig, pk) + } + } + return +} + +// get claimed public key from handshake +func getPubkey(hs []byte) (pk []byte) { + ml := len(protocol_magic) + pl := CryptoSignPublicLen() + pk = hs[ml : ml+pl] + return +} + +func (cs *CryptoStream) genHandshake() (d []byte) { + // protocol magic string version 00 + // Benis Encrypted Network Information Stream + // :-DDDDD meme crypto + d = append(d, protocol_magic...) + // our public key + d = append(d, cs.public()...) + // nounce + cs.tx_nonce = NewBoxNounce() + d = append(d, cs.tx_nonce...) + // sign protocol magic string, nounce and pubkey + sig := CryptoSignFucky(d, cs.secret()) + // if sig is nil we'll just die + d = append(d, sig...) + return +} + +// extract nounce from handshake +func getNounce(hs []byte) (n []byte) { + ml := len(protocol_magic) + pl := CryptoSignPublicLen() + nl := NounceLen() + n = hs[ml+pl : ml+pl+nl] + return +} + +// initiate protocol handshake +func (cs *CryptoStream) Handshake() (err error) { + // send them our info + hs := cs.genHandshake() + var n int + n, err = cs.stream.Write(hs) + if n != len(hs) { + err = ShortWrite + return + } + // read thier info + buff := make([]byte, len(hs)) + _, err = io.ReadFull(cs.stream, buff) + + if cs.remote_pk == nil { + // inbound + pk := getPubkey(buff) + cs.remote_pk = make([]byte, len(pk)) + copy(cs.remote_pk, pk) + } + + if !verifyHandshake(buff, cs.remote_pk) { + // verification failed + err = BadHandshake + return + } + cs.rx_nonce = make([]byte, NounceLen()) + copy(cs.rx_nonce, getNounce(buff)) + return +} + +// create a client +func Client(stream io.ReadWriteCloser, local_sk, remote_pk []byte) (c *CryptoStream) { + c = &CryptoStream{ + stream: stream, + mtu: DefaultMTU, + } + c.remote_pk = make([]byte, len(remote_pk)) + copy(c.remote_pk, remote_pk) + c.key = LoadSignKey(local_sk) + if c.key == nil { + return nil + } + return c +} + +type CryptoConn struct { + stream *CryptoStream + conn net.Conn +} + +func (cc *CryptoConn) Close() (err error) { + err = cc.stream.Close() + return +} + +func (cc *CryptoConn) Write(d []byte) (n int, err error) { + return cc.stream.Write(d) +} + +func (cc *CryptoConn) Read(d []byte) (n int, err error) { + return cc.stream.Read(d) +} + +func (cc *CryptoConn) LocalAddr() net.Addr { + return cc.conn.LocalAddr() +} + +func (cc *CryptoConn) RemoteAddr() net.Addr { + return cc.conn.RemoteAddr() +} + +func (cc *CryptoConn) SetDeadline(t time.Time) (err error) { + return cc.conn.SetDeadline(t) +} + +func (cc *CryptoConn) SetReadDeadline(t time.Time) (err error) { + return cc.conn.SetReadDeadline(t) +} + +func (cc *CryptoConn) SetWriteDeadline(t time.Time) (err error) { + return cc.conn.SetWriteDeadline(t) +} + +type CryptoListener struct { + l net.Listener + handshake chan net.Conn + accepted chan *CryptoConn + trust func(pk []byte) bool + key *KeyPair +} + +func (cl *CryptoListener) Close() (err error) { + err = cl.l.Close() + close(cl.accepted) + close(cl.handshake) + cl.key.Free() + cl.key = nil + return +} + +func (cl *CryptoListener) acceptInbound() { + for { + c, err := cl.l.Accept() + if err == nil { + cl.handshake <- c + } else { + return + } + } +} + +func (cl *CryptoListener) runChans() { + for { + select { + case c := <-cl.handshake: + go func() { + s := &CryptoStream{ + stream: c, + mtu: DefaultMTU, + key: cl.key, + } + err := s.Handshake() + if err == nil { + // we gud handshake was okay + if cl.trust(s.remote_pk) { + // the key is trusted okay + cl.accepted <- &CryptoConn{stream: s, conn: c} + } else { + // not trusted, close connection + s.Close() + } + } + }() + } + } +} + +// accept inbound authenticated and trusted connections +func (cl *CryptoListener) Accept() (c net.Conn, err error) { + var ok bool + c, ok = <-cl.accepted + if !ok { + err = Closed + } + return +} + +// create a listener +func Server(l net.Listener, local_sk []byte, trust func(pk []byte) bool) (s *CryptoListener) { + s = &CryptoListener{ + l: l, + trust: trust, + handshake: make(chan net.Conn), + accepted: make(chan *CryptoConn), + } + s.key = LoadSignKey(local_sk) + go s.runChans() + go s.acceptInbound() + return +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/crypto/nacl/verfiy.go b/contrib/backends/nntpchand/src/nntpchan/lib/crypto/nacl/verfiy.go new file mode 100644 index 0000000..9b86347 --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/crypto/nacl/verfiy.go @@ -0,0 +1,53 @@ +package nacl + +// #cgo freebsd CFLAGS: -I/usr/local/include +// #cgo freebsd LDFLAGS: -L/usr/local/lib +// #cgo LDFLAGS: -lsodium +// #include +import "C" + +// verify a fucky detached sig +func CryptoVerifyFucky(msg, sig, pk []byte) bool { + var smsg []byte + smsg = append(smsg, sig...) + smsg = append(smsg, msg...) + return CryptoVerify(smsg, pk) +} + +// verify a signed message +func CryptoVerify(smsg, pk []byte) bool { + smsg_buff := NewBuffer(smsg) + defer smsg_buff.Free() + pk_buff := NewBuffer(pk) + defer pk_buff.Free() + + if pk_buff.size != C.crypto_sign_publickeybytes() { + return false + } + mlen := C.ulonglong(0) + msg := malloc(C.size_t(len(smsg))) + defer msg.Free() + smlen := C.ulonglong(smsg_buff.size) + return C.crypto_sign_open(msg.uchar(), &mlen, smsg_buff.uchar(), smlen, pk_buff.uchar()) != -1 +} + +// verfiy a detached signature +// return true on valid otherwise false +func CryptoVerifyDetached(msg, sig, pk []byte) bool { + msg_buff := NewBuffer(msg) + defer msg_buff.Free() + sig_buff := NewBuffer(sig) + defer sig_buff.Free() + pk_buff := NewBuffer(pk) + defer pk_buff.Free() + + if pk_buff.size != C.crypto_sign_publickeybytes() { + return false + } + + // invalid sig size + if sig_buff.size != C.crypto_sign_bytes() { + return false + } + return C.crypto_sign_verify_detached(sig_buff.uchar(), msg_buff.uchar(), C.ulonglong(len(msg)), pk_buff.uchar()) == 0 +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/crypto/nacl_test.go b/contrib/backends/nntpchand/src/nntpchan/lib/crypto/nacl_test.go new file mode 100644 index 0000000..6028654 --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/crypto/nacl_test.go @@ -0,0 +1,34 @@ +package crypto + +import ( + "bytes" + "crypto/rand" + "io" + "testing" +) + +func TestNaclToPublic(t *testing.T) { + pk, sk := GenKeypair() + t_pk := ToPublic(sk) + if !bytes.Equal(pk, t_pk) { + t.Logf("%q != %q", pk, t_pk) + t.Fail() + } +} + +func TestNaclSignVerify(t *testing.T) { + var msg [1024]byte + pk, sk := GenKeypair() + io.ReadFull(rand.Reader, msg[:]) + + signer := CreateSigner(sk) + signer.Write(msg[:]) + sig := signer.Sign() + + verifier := CreateVerifier(pk) + verifier.Write(msg[:]) + if !verifier.Verify(sig) { + t.Logf("%q is invalid signature and is %dB long", sig, len(sig)) + t.Fail() + } +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/crypto/rand.go b/contrib/backends/nntpchand/src/nntpchan/lib/crypto/rand.go new file mode 100644 index 0000000..2c854c5 --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/crypto/rand.go @@ -0,0 +1,8 @@ +package crypto + +import ( + "nntpchan/lib/crypto/nacl" +) + +// generate random bytes +var RandBytes = nacl.RandBytes diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/crypto/sig.go b/contrib/backends/nntpchand/src/nntpchan/lib/crypto/sig.go new file mode 100644 index 0000000..4fc3178 --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/crypto/sig.go @@ -0,0 +1,25 @@ +package crypto + +import "io" + +// a detached signature +type Signature []byte + +type SigEncoder interface { + // encode a signature to an io.Writer + // return error if one occurrened while writing out signature + Encode(sig Signature, w io.Writer) error + // encode a signature to a string + EncodeString(sig Signature) string +} + +// a decoder of signatures +type SigDecoder interface { + // decode signature from io.Reader + // reads all data until io.EOF + // returns singaure or error if an error occured while reading + Decode(r io.Reader) (Signature, error) + // decode a signature from string + // returns signature or error if an error ocurred while decoding + DecodeString(str string) (Signature, error) +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/crypto/sign.go b/contrib/backends/nntpchand/src/nntpchan/lib/crypto/sign.go new file mode 100644 index 0000000..2f00d62 --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/crypto/sign.go @@ -0,0 +1,14 @@ +package crypto + +import "io" + +// +// provides generic signing interface for producing detached signatures +// call Write() to feed data to be signed, call Sign() to generate +// a detached signature +// +type Signer interface { + io.Writer + // generate detached Signature from previously fed body via Write() + Sign() Signature +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/crypto/verify.go b/contrib/backends/nntpchand/src/nntpchan/lib/crypto/verify.go new file mode 100644 index 0000000..90b941b --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/crypto/verify.go @@ -0,0 +1,14 @@ +package crypto + +import "io" + +// provides generic signature +// call Write() to feed in message body +// once the entire body has been fed in via Write() call Verify() with detached +// signature to verify the detached signature against the previously fed body +type Verifer interface { + io.Writer + // verify detached signature from body previously fed via Write() + // return true if the detached signature is valid given the body + Verify(sig Signature) bool +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/database/database.go b/contrib/backends/nntpchand/src/nntpchan/lib/database/database.go new file mode 100644 index 0000000..4d2f284 --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/database/database.go @@ -0,0 +1,26 @@ +package database + +import ( + "errors" + "nntpchan/lib/config" + "nntpchan/lib/model" + "strings" +) + +// +type Database interface { + ThreadByMessageID(msgid string) (*model.Thread, error) + ThreadByHash(hash string) (*model.Thread, error) + BoardPage(newsgroup string, pageno, perpage int) (*model.BoardPage, error) +} + +// get new database connector from configuration +func NewDBFromConfig(c *config.DatabaseConfig) (db Database, err error) { + dbtype := strings.ToLower(c.Type) + if dbtype == "postgres" { + db, err = createPostgresDatabase(c.Addr, c.Username, c.Password) + } else { + err = errors.New("no such database driver: " + c.Type) + } + return +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/database/doc.go b/contrib/backends/nntpchand/src/nntpchan/lib/database/doc.go new file mode 100644 index 0000000..bfd8b14 --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/database/doc.go @@ -0,0 +1,4 @@ +// +// database driver +// +package database diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/database/postgres.go b/contrib/backends/nntpchand/src/nntpchan/lib/database/postgres.go new file mode 100644 index 0000000..a1b6a51 --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/database/postgres.go @@ -0,0 +1,28 @@ +package database + +import ( + "nntpchan/lib/model" +) + +type PostgresDB struct { +} + +func (db *PostgresDB) ThreadByMessageID(msgid string) (thread *model.Thread, err error) { + + return +} + +func (db *PostgresDB) ThreadByHash(hash string) (thread *model.Thread, err error) { + + return +} + +func (db *PostgresDB) BoardPage(newsgroup string, pageno, perpage int) (page *model.BoardPage, err error) { + + return +} + +func createPostgresDatabase(addr, user, passwd string) (p *PostgresDB, err error) { + + return +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/frontend/captcha.go b/contrib/backends/nntpchand/src/nntpchan/lib/frontend/captcha.go new file mode 100644 index 0000000..f4f05fd --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/frontend/captcha.go @@ -0,0 +1,123 @@ +package frontend + +import ( + "encoding/json" + "errors" + "fmt" + "github.com/dchest/captcha" + "github.com/gorilla/mux" + "github.com/gorilla/sessions" + "net/http" + "nntpchan/lib/config" +) + +// server of captchas +// implements frontend.Middleware +type CaptchaServer struct { + h int + w int + store *sessions.CookieStore + prefix string + sessionName string +} + +// create new captcha server using existing session store +func NewCaptchaServer(w, h int, prefix string, store *sessions.CookieStore) *CaptchaServer { + return &CaptchaServer{ + h: h, + w: w, + prefix: prefix, + store: store, + sessionName: "captcha", + } +} + +func (cs *CaptchaServer) Reload(c *config.MiddlewareConfig) { + +} + +func (cs *CaptchaServer) SetupRoutes(m *mux.Router) { + m.Path("/new").HandlerFunc(cs.NewCaptcha) + m.Path("/img/{f}").Handler(captcha.Server(cs.w, cs.h)) + m.Path("/verify.json").HandlerFunc(cs.VerifyCaptcha) +} + +// return true if this session has solved the last captcha given provided solution, otherwise false +func (cs *CaptchaServer) CheckSession(w http.ResponseWriter, r *http.Request, solution string) (bool, error) { + s, err := cs.store.Get(r, cs.sessionName) + if err == nil { + id, ok := s.Values["captcha_id"] + if ok { + return captcha.VerifyString(id.(string), solution), nil + } + } + return false, err +} + +// verify a captcha +func (cs *CaptchaServer) VerifyCaptcha(w http.ResponseWriter, r *http.Request) { + dec := json.NewDecoder(r.Body) + defer r.Body.Close() + // request + req := make(map[string]string) + // response + resp := make(map[string]interface{}) + resp["solved"] = false + // decode request + err := dec.Decode(req) + if err == nil { + // decode okay + id, ok := req["id"] + if ok { + // we have id + solution, ok := req["solution"] + if ok { + // we have solution and id + resp["solved"] = captcha.VerifyString(id, solution) + } else { + // we don't have solution + err = errors.New("no captcha solution provided") + } + } else { + // we don't have id + err = errors.New("no captcha id provided") + } + } + if err != nil { + // error happened + resp["error"] = err.Error() + } + // send reply + w.Header().Set("Content-Type", "text/json; encoding=UTF-8") + enc := json.NewEncoder(w) + enc.Encode(resp) +} + +// generate a new captcha +func (cs *CaptchaServer) NewCaptcha(w http.ResponseWriter, r *http.Request) { + // obtain session + sess, err := cs.store.Get(r, cs.sessionName) + if err != nil { + // failed to obtain session + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + // new captcha + id := captcha.New() + // do we want to interpret as json? + use_json := r.URL.Query().Get("t") == "json" + // image url + url := fmt.Sprintf("%simg/%s.png", cs.prefix, id) + if use_json { + // send json + enc := json.NewEncoder(w) + enc.Encode(map[string]string{"id": id, "url": url}) + } else { + // set captcha id + sess.Values["captcha_id"] = id + // save session + sess.Save(r, w) + // rediect to image + http.Redirect(w, r, url, http.StatusFound) + } +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/frontend/doc.go b/contrib/backends/nntpchand/src/nntpchan/lib/frontend/doc.go new file mode 100644 index 0000000..72b3f40 --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/frontend/doc.go @@ -0,0 +1,5 @@ +// +// nntpchan frontend +// allows posting to nntpchan network via various implementations +// +package frontend diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/frontend/frontend.go b/contrib/backends/nntpchand/src/nntpchan/lib/frontend/frontend.go new file mode 100644 index 0000000..77da159 --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/frontend/frontend.go @@ -0,0 +1,46 @@ +package frontend + +import ( + "nntpchan/lib/config" + "nntpchan/lib/database" + "nntpchan/lib/model" + "nntpchan/lib/nntp" +) + +// a frontend that displays nntp posts and allows posting +type Frontend interface { + + // run mainloop + Serve() + + // do we accept this inbound post? + AllowPost(p model.PostReference) bool + + // trigger a manual regen of indexes for a root post + Regen(p model.PostReference) + + // implements nntp.EventHooks + GotArticle(msgid nntp.MessageID, group nntp.Newsgroup) + + // implements nntp.EventHooks + SentArticleVia(msgid nntp.MessageID, feedname string) + + // reload config + Reload(c *config.FrontendConfig) +} + +// create a new http frontend give frontend config +func NewHTTPFrontend(c *config.FrontendConfig, db database.Database) (f Frontend, err error) { + + var mid Middleware + if c.Middleware != nil { + // middleware configured + mid, err = OverchanMiddleware(c.Middleware, db) + } + + if err == nil { + // create http frontend only if no previous errors + f, err = createHttpFrontend(c, mid, db) + } + return +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/frontend/http.go b/contrib/backends/nntpchand/src/nntpchan/lib/frontend/http.go new file mode 100644 index 0000000..6096911 --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/frontend/http.go @@ -0,0 +1,136 @@ +package frontend + +import ( + "fmt" + log "github.com/Sirupsen/logrus" + "github.com/gorilla/mux" + "net/http" + "nntpchan/lib/admin" + "nntpchan/lib/api" + "nntpchan/lib/config" + "nntpchan/lib/database" + "nntpchan/lib/model" + "nntpchan/lib/nntp" + "time" +) + +// http frontend server +// provides glue layer between nntp and middleware +type httpFrontend struct { + // bind address + addr string + // http mux + httpmux *mux.Router + // admin panel + adminPanel *admin.Server + // static files path + staticDir string + // http middleware + middleware Middleware + // api server + apiserve *api.Server + // database driver + db database.Database +} + +// reload http frontend +// reloads middleware +func (f *httpFrontend) Reload(c *config.FrontendConfig) { + if f.middleware == nil { + if c.Middleware != nil { + var err error + // no middleware set, create middleware + f.middleware, err = OverchanMiddleware(c.Middleware, f.db) + if err != nil { + log.Errorf("overchan middleware reload failed: %s", err.Error()) + } + + } + } else { + // middleware exists + // do middleware reload + f.middleware.Reload(c.Middleware) + } + +} + +// serve http requests from net.Listener +func (f *httpFrontend) Serve() { + // serve http + for { + err := http.ListenAndServe(f.addr, f.httpmux) + if err != nil { + log.Errorf("failed to listen and serve with frontend: %s", err) + } + time.Sleep(time.Second) + } +} + +// serve robots.txt page +func (f *httpFrontend) serveRobots(w http.ResponseWriter, r *http.Request) { + fmt.Fprintf(w, "User-Agent: *\nDisallow: /\n") +} + +func (f *httpFrontend) AllowPost(p model.PostReference) bool { + // TODO: implement + return true +} + +func (f *httpFrontend) Regen(p model.PostReference) { + // TODO: implement +} + +func (f *httpFrontend) GotArticle(msgid nntp.MessageID, group nntp.Newsgroup) { + // TODO: implement +} + +func (f *httpFrontend) SentArticleVia(msgid nntp.MessageID, feedname string) { + // TODO: implement +} + +func createHttpFrontend(c *config.FrontendConfig, mid Middleware, db database.Database) (f *httpFrontend, err error) { + f = new(httpFrontend) + // set db + // db.Ensure() called elsewhere + f.db = db + + // set bind address + f.addr = c.BindAddr + + // set up mux + f.httpmux = mux.NewRouter() + + // set up admin panel + f.adminPanel = admin.NewServer() + + // set static files dir + f.staticDir = c.Static + + // set middleware + f.middleware = mid + + // set up routes + + if f.adminPanel != nil { + // route up admin panel + f.httpmux.PathPrefix("/admin/").Handler(f.adminPanel) + } + + if f.middleware != nil { + // route up middleware + f.middleware.SetupRoutes(f.httpmux) + } + + if f.apiserve != nil { + // route up api + f.apiserve.SetupRoutes(f.httpmux.PathPrefix("/api/").Subrouter()) + } + + // route up robots.txt + f.httpmux.Path("/robots.txt").HandlerFunc(f.serveRobots) + + // route up static files + f.httpmux.PathPrefix("/static/").Handler(http.FileServer(http.Dir(f.staticDir))) + + return +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/frontend/middleware.go b/contrib/backends/nntpchand/src/nntpchan/lib/frontend/middleware.go new file mode 100644 index 0000000..4c8abba --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/frontend/middleware.go @@ -0,0 +1,14 @@ +package frontend + +import ( + "github.com/gorilla/mux" + "nntpchan/lib/config" +) + +// http middleware +type Middleware interface { + // set up routes + SetupRoutes(m *mux.Router) + // reload with new configuration + Reload(c *config.MiddlewareConfig) +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/frontend/overchan.go b/contrib/backends/nntpchand/src/nntpchan/lib/frontend/overchan.go new file mode 100644 index 0000000..b16347c --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/frontend/overchan.go @@ -0,0 +1,115 @@ +package frontend + +import ( + log "github.com/Sirupsen/logrus" + "github.com/gorilla/mux" + "github.com/gorilla/sessions" + "html/template" + "net/http" + "nntpchan/lib/config" + "nntpchan/lib/database" + "path/filepath" + "strconv" +) + +// standard overchan imageboard middleware +type overchanMiddleware struct { + templ *template.Template + captcha *CaptchaServer + store *sessions.CookieStore + db database.Database +} + +func (m *overchanMiddleware) SetupRoutes(mux *mux.Router) { + // setup front page handler + mux.Path("/").HandlerFunc(m.ServeIndex) + // setup thread handler + mux.Path("/t/{id}/").HandlerFunc(m.ServeThread) + // setup board page handler + mux.Path("/b/{name}/").HandlerFunc(m.ServeBoardPage) + // setup posting endpoint + mux.Path("/post") + // create captcha + captchaPrefix := "/captcha/" + m.captcha = NewCaptchaServer(200, 400, captchaPrefix, m.store) + // setup captcha endpoint + m.captcha.SetupRoutes(mux.PathPrefix(captchaPrefix).Subrouter()) +} + +// reload middleware +func (m *overchanMiddleware) Reload(c *config.MiddlewareConfig) { + // reload templates + templ, err := template.ParseGlob(filepath.Join(c.Templates, "*.tmpl")) + if err == nil { + log.Infof("middleware reloaded templates") + m.templ = templ + } else { + log.Errorf("middleware reload failed: %s", err.Error()) + } +} + +func (m *overchanMiddleware) ServeBoardPage(w http.ResponseWriter, r *http.Request) { + param := mux.Vars(r) + board := param["name"] + page := r.URL.Query().Get("q") + pageno, err := strconv.Atoi(page) + if err == nil { + var obj interface{} + obj, err = m.db.BoardPage(board, pageno, 10) + if err == nil { + m.serveTemplate(w, r, "board.html.tmpl", obj) + } else { + m.serveTemplate(w, r, "error.html.tmpl", err) + } + } else { + // 404 + http.NotFound(w, r) + } +} + +// serve cached thread +func (m *overchanMiddleware) ServeThread(w http.ResponseWriter, r *http.Request) { + param := mux.Vars(r) + obj, err := m.db.ThreadByHash(param["id"]) + if err == nil { + m.serveTemplate(w, r, "thread.html.tmpl", obj) + } else { + m.serveTemplate(w, r, "error.html.tmpl", err) + } +} + +// serve index page +func (m *overchanMiddleware) ServeIndex(w http.ResponseWriter, r *http.Request) { + m.serveTemplate(w, r, "index.html.tmpl", nil) +} + +// serve a template +func (m *overchanMiddleware) serveTemplate(w http.ResponseWriter, r *http.Request, tname string, obj interface{}) { + t := m.templ.Lookup(tname) + if t == nil { + log.WithFields(log.Fields{ + "template": tname, + }).Warning("template not found") + http.NotFound(w, r) + } else { + err := t.Execute(w, obj) + if err != nil { + // error getting model + log.WithFields(log.Fields{ + "error": err, + "template": tname, + }).Warning("failed to render template") + } + } +} + +// create standard overchan middleware +func OverchanMiddleware(c *config.MiddlewareConfig, db database.Database) (m Middleware, err error) { + om := new(overchanMiddleware) + om.templ, err = template.ParseGlob(filepath.Join(c.Templates, "*.tmpl")) + om.db = db + if err == nil { + m = om + } + return +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/frontend/post.go b/contrib/backends/nntpchand/src/nntpchan/lib/frontend/post.go new file mode 100644 index 0000000..d698e76 --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/frontend/post.go @@ -0,0 +1 @@ +package frontend diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/frontend/webhooks.go b/contrib/backends/nntpchand/src/nntpchan/lib/frontend/webhooks.go new file mode 100644 index 0000000..d698e76 --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/frontend/webhooks.go @@ -0,0 +1 @@ +package frontend diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/model/article.go b/contrib/backends/nntpchand/src/nntpchan/lib/model/article.go new file mode 100644 index 0000000..237f9eb --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/model/article.go @@ -0,0 +1,15 @@ +package model + +type Article struct { + Subject string + Name string + Header map[string][]string + Text string + Attachments []Attachment + MessageID string + Newsgroup string + Reference string + Path string + Posted int64 + Addr string +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/model/attachment.go b/contrib/backends/nntpchand/src/nntpchan/lib/model/attachment.go new file mode 100644 index 0000000..dd43fc7 --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/model/attachment.go @@ -0,0 +1,10 @@ +package model + +type Attachment struct { + Path string + Name string + Mime string + Hash string + // only filled for api + Body string +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/model/board.go b/contrib/backends/nntpchand/src/nntpchan/lib/model/board.go new file mode 100644 index 0000000..ea1f829 --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/model/board.go @@ -0,0 +1,4 @@ +package model + +type Board struct { +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/model/boardpage.go b/contrib/backends/nntpchand/src/nntpchan/lib/model/boardpage.go new file mode 100644 index 0000000..f335743 --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/model/boardpage.go @@ -0,0 +1,8 @@ +package model + +type BoardPage struct { + Name string + Page int + Pages int + Threads []Thread +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/model/doc.go b/contrib/backends/nntpchand/src/nntpchan/lib/model/doc.go new file mode 100644 index 0000000..8bef866 --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/model/doc.go @@ -0,0 +1,2 @@ +// MVC models +package model diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/model/misc.go b/contrib/backends/nntpchand/src/nntpchan/lib/model/misc.go new file mode 100644 index 0000000..2259e85 --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/model/misc.go @@ -0,0 +1,29 @@ +package model + +import ( + "time" +) + +type ArticleHeader map[string][]string + +// a ( MessageID , newsgroup ) tuple +type ArticleEntry [2]string + +func (self ArticleEntry) Newsgroup() string { + return self[1] +} + +func (self ArticleEntry) MessageID() string { + return self[0] +} + +// a ( time point, post count ) tuple +type PostEntry [2]int64 + +func (self PostEntry) Time() time.Time { + return time.Unix(self[0], 0) +} + +func (self PostEntry) Count() int64 { + return self[1] +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/model/post.go b/contrib/backends/nntpchand/src/nntpchan/lib/model/post.go new file mode 100644 index 0000000..dfa1f09 --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/model/post.go @@ -0,0 +1,32 @@ +package model + +import ( + "time" +) + +type Tripcode string + +type Post struct { + MessageID string + Newsgroup string + Attachments []Attachment + Subject string + Posted time.Time + PostedAt uint64 + Name string + Tripcode Tripcode +} + +// ( message-id, references, newsgroup ) +type PostReference [3]string + +func (r PostReference) MessageID() string { + return r[0] +} + +func (r PostReference) References() string { + return r[1] +} +func (r PostReference) Newsgroup() string { + return r[2] +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/model/thread.go b/contrib/backends/nntpchand/src/nntpchan/lib/model/thread.go new file mode 100644 index 0000000..6a6b894 --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/model/thread.go @@ -0,0 +1,6 @@ +package model + +type Thread struct { + Root *Post + Replies []*Post +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/network/dial.go b/contrib/backends/nntpchand/src/nntpchan/lib/network/dial.go new file mode 100644 index 0000000..f280a40 --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/network/dial.go @@ -0,0 +1,37 @@ +package network + +import ( + "errors" + "net" + "nntpchan/lib/config" + "strings" +) + +// operation timed out +var ErrTimeout = errors.New("timeout") + +// the operation was reset abruptly +var ErrReset = errors.New("reset") + +// the operation was actively refused +var ErrRefused = errors.New("refused") + +// generic dialer +// dials out to a remote address +// returns a net.Conn and nil on success +// returns nil and error if an error happens while dialing +type Dialer interface { + Dial(remote string) (net.Conn, error) +} + +// create a new dialer from configuration +func NewDialer(conf *config.ProxyConfig) (d Dialer) { + d = StdDialer + if conf != nil { + proxyType := strings.ToLower(conf.Type) + if proxyType == "socks" || proxyType == "socks4a" { + d = SocksDialer(conf.Addr) + } + } + return +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/network/doc.go b/contrib/backends/nntpchand/src/nntpchan/lib/network/doc.go new file mode 100644 index 0000000..ab242ea --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/network/doc.go @@ -0,0 +1,4 @@ +// +// network utilities +// +package network diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/network/i2p.go b/contrib/backends/nntpchand/src/nntpchan/lib/network/i2p.go new file mode 100644 index 0000000..1ae2e9d --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/network/i2p.go @@ -0,0 +1 @@ +package network diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/network/socks.go b/contrib/backends/nntpchand/src/nntpchan/lib/network/socks.go new file mode 100644 index 0000000..44b5d4c --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/network/socks.go @@ -0,0 +1,140 @@ +package network + +import ( + "errors" + log "github.com/Sirupsen/logrus" + "io" + "net" + "strconv" + "strings" +) + +type socksDialer struct { + socksAddr string + dialer Dialer +} + +// try dialing out via socks proxy +func (sd *socksDialer) Dial(remote string) (c net.Conn, err error) { + log.WithFields(log.Fields{ + "addr": remote, + "socks": sd.socksAddr, + }).Debug("dailing out to socks proxy") + c, err = sd.dialer.Dial(sd.socksAddr) + if err == nil { + // dailed out to socks proxy good + remote_addr := remote + // generate request + idx := strings.LastIndex(remote_addr, ":") + if idx == -1 { + err = errors.New("invalid address: " + remote_addr) + return + } + var port uint64 + addr := remote_addr[:idx] + port, err = strconv.ParseUint(remote_addr[idx+1:], 10, 16) + if port >= 25536 { + err = errors.New("bad proxy port") + c.Close() + c = nil + return + } else if err != nil { + c.Close() + return + } + var proxy_port uint16 + proxy_port = uint16(port) + proxy_ident := "srndproxy" + req_len := len(addr) + 1 + len(proxy_ident) + 1 + 8 + + req := make([]byte, req_len) + // pack request + req[0] = '\x04' + req[1] = '\x01' + req[2] = byte(proxy_port & 0xff00 >> 8) + req[3] = byte(proxy_port & 0x00ff) + req[7] = '\x01' + idx = 8 + + proxy_ident_b := []byte(proxy_ident) + addr_b := []byte(addr) + + var bi int + for bi = range proxy_ident_b { + req[idx] = proxy_ident_b[bi] + idx += 1 + } + idx += 1 + for bi = range addr_b { + req[idx] = addr_b[bi] + idx += 1 + } + log.WithFields(log.Fields{ + "addr": remote, + "socks": sd.socksAddr, + "req": req, + }).Debug("write socks request") + n := 0 + n, err = c.Write(req) + if err == nil && n == len(req) { + // wrote request okay + resp := make([]byte, 8) + _, err = io.ReadFull(c, resp) + if err == nil { + // got reply okay + if resp[1] == '\x5a' { + // successful socks connection + log.WithFields(log.Fields{ + "addr": remote, + "socks": sd.socksAddr, + }).Debug("socks proxy connection successful") + } else { + // unsucessful socks connect + log.WithFields(log.Fields{ + "addr": remote, + "socks": sd.socksAddr, + "code": resp[1], + }).Warn("connect via socks proxy failed") + c.Close() + c = nil + } + } else { + // error reading reply + log.WithFields(log.Fields{ + "addr": remote, + "socks": sd.socksAddr, + }).Error("failed to read socks response ", err) + c.Close() + c = nil + } + } else { + if err == nil { + err = errors.New("short write") + } + + // error writing request + log.WithFields(log.Fields{ + "addr": remote, + "socks": sd.socksAddr, + }).Error("failed to write socks request ", err) + c.Close() + c = nil + + } + } else { + // dail fail + log.WithFields(log.Fields{ + "addr": remote, + "socks": sd.socksAddr, + }).Error("Cannot connect to socks proxy ", err) + } + return +} + +// create a socks dialer that dials out via socks proxy at address +func SocksDialer(addr string) Dialer { + return &socksDialer{ + socksAddr: addr, + dialer: StdDialer, + } +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/network/std.go b/contrib/backends/nntpchand/src/nntpchan/lib/network/std.go new file mode 100644 index 0000000..134d079 --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/network/std.go @@ -0,0 +1,14 @@ +package network + +import ( + "net" +) + +type stdDialer struct { +} + +func (sd *stdDialer) Dial(addr string) (c net.Conn, err error) { + return net.Dial("tcp", addr) +} + +var StdDialer = &stdDialer{} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/nntp/acceptor.go b/contrib/backends/nntpchand/src/nntpchan/lib/nntp/acceptor.go new file mode 100644 index 0000000..fc74fdd --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/nntp/acceptor.go @@ -0,0 +1,69 @@ +package nntp + +import ( + "nntpchan/lib/nntp/message" +) + +const ( + // accepted article + ARTICLE_ACCEPT = iota + // reject article, don't send again + ARTICLE_REJECT + // defer article, send later + ARTICLE_DEFER + // reject + ban + ARTICLE_BAN +) + +type PolicyStatus int + +const PolicyAccept = PolicyStatus(ARTICLE_ACCEPT) +const PolicyReject = PolicyStatus(ARTICLE_REJECT) +const PolicyDefer = PolicyStatus(ARTICLE_DEFER) +const PolicyBan = PolicyStatus(ARTICLE_BAN) + +func (s PolicyStatus) String() string { + switch int(s) { + case ARTICLE_ACCEPT: + return "ACCEPTED" + case ARTICLE_REJECT: + return "REJECTED" + case ARTICLE_DEFER: + return "DEFERRED" + case ARTICLE_BAN: + return "BANNED" + default: + return "[invalid policy status]" + } +} + +// is this an accept code? +func (s PolicyStatus) Accept() bool { + return s == ARTICLE_ACCEPT +} + +// is this a defer code? +func (s PolicyStatus) Defer() bool { + return s == ARTICLE_DEFER +} + +// is this a ban code +func (s PolicyStatus) Ban() bool { + return s == ARTICLE_BAN +} + +// is this a reject code? +func (s PolicyStatus) Reject() bool { + return s == ARTICLE_BAN || s == ARTICLE_REJECT +} + +// type defining a policy that determines if we want to accept/reject/defer an +// incoming article +type ArticleAcceptor interface { + // check article given an article header + CheckHeader(hdr message.Header) PolicyStatus + // check article given a message id + CheckMessageID(msgid MessageID) PolicyStatus + // get max article size in bytes + MaxArticleSize() int64 +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/nntp/auth.go b/contrib/backends/nntpchand/src/nntpchan/lib/nntp/auth.go new file mode 100644 index 0000000..65d0f00 --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/nntp/auth.go @@ -0,0 +1,38 @@ +package nntp + +import ( + "bufio" + "fmt" + "os" + "strings" +) + +// defines server side authentication mechanism +type ServerAuth interface { + // check plaintext login + // returns nil on success otherwise error if one occurs during authentication + // returns true if authentication was successful and an error if a network io error happens + CheckLogin(username, passwd string) (bool, error) +} + +type FlatfileAuth string + +func (fname FlatfileAuth) CheckLogin(username, passwd string) (found bool, err error) { + cred := fmt.Sprintf("%s:%s", username, passwd) + var f *os.File + f, err = os.Open(string(fname)) + if err == nil { + defer f.Close() + r := bufio.NewReader(f) + for err == nil { + var line string + line, err = r.ReadString(10) + line = strings.Trim(line, "\r\n") + if line == cred { + found = true + break + } + } + } + return +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/nntp/codes.go b/contrib/backends/nntpchand/src/nntpchan/lib/nntp/codes.go new file mode 100644 index 0000000..fb0f9e6 --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/nntp/codes.go @@ -0,0 +1,206 @@ +package nntp + +// 1xx codes + +// help info follows +const RPL_Help = "100" + +// capabilities info follows +const RPL_Capabilities = "101" + +// server date time follows +const RPL_Date = "111" + +// 2xx codes + +// posting is allowed +const RPL_PostingAllowed = "200" + +// posting is not allowed +const RPL_PostingNotAllowed = "201" + +// streaming mode enabled +const RPL_PostingStreaming = "203" + +// reply to QUIT command, we will close the connection +const RPL_Quit = "205" + +// reply for GROUP and LISTGROUP commands +const RPL_Group = "211" + +// info list follows +const RPL_List = "215" + +// index follows +const RPL_Index = "218" + +// article follows +const RPL_Article = "220" + +// article headers follows +const RPL_ArticleHeaders = "221" + +// article body follows +const RPL_ArticleBody = "222" + +// selected article exists +const RPL_ArticleSelectedExists = "223" + +// overview info follows +const RPL_Overview = "224" + +// list of article heards follows +const RPL_HeadersList = "225" + +// list of new articles follows +const RPL_NewArticles = "230" + +// list of newsgroups followes +const RPL_NewsgroupList = "231" + +// article was transfered okay by IHAVE command +const RPL_TransferOkay = "235" + +// article is not found by CHECK and we want it +const RPL_StreamingAccept = "238" + +// article was transfered via TAKETHIS successfully +const RPL_StreamingTransfered = "239" + +// article was transfered by POST command successfully +const RPL_PostReceived = "240" + +// AUTHINFO SIMPLE accepted +const RPL_AuthInfoAccepted = "250" + +// authentication creds have been accepted +const RPL_AuthAccepted = "281" + +// binary content follows +const RPL_Binary = "288" + +// line sent for posting allowed +const Line_PostingAllowed = RPL_PostingAllowed + " Posting Allowed" + +// line sent for posting not allowed +const Line_PostingNotAllowed = RPL_PostingNotAllowed + " Posting Not Allowed" + +// 3xx codes + +// article is accepted via IHAVE +const RPL_TransferAccepted = "335" + +// article was accepted via POST +const RPL_PostAccepted = "340" + +// continue with authorization +const RPL_ContinueAuthorization = "350" + +// more authentication info required +const RPL_MoreAuth = "381" + +// continue with tls handshake +const RPL_TLSContinue = "382" + +// 4xx codes + +// server says servive is not avaiable on initial connection +const RPL_NotAvaiable = "400" + +// server is in the wrong mode +const RPL_WrongMode = "401" + +// generic fault prevent action from being taken +const RPL_GenericError = "403" + +// newsgroup does not exist +const RPL_NoSuchGroup = "411" + +// no newsgroup has been selected +const RPL_NoGroupSelected = "412" + +// no tin style index available +const RPL_NoIndex = "418" + +// current article number is invalid +const RPL_NoArticleNum = "420" + +// no next article in this group (NEXT) +const RPL_NoNextArticle = "421" + +// no previous article in this group (LAST) +const RPL_NoPrevArticle = "422" + +// no article in specified range +const RPL_NoArticleRange = "423" + +// no article with that message-id +const RPL_NoArticleMsgID = "430" + +// defer article asked by CHECK comamnd +const RPL_StreamingDefer = "431" + +// article is not wanted (1st stage of IHAVE) +const RPL_TransferNotWanted = "435" + +// article was not sent defer sending (either stage of IHAVE) +const RPL_TransferDefer = "436" + +// reject transfer do not retry (2nd stage IHAVE) +const RPL_TransferReject = "437" + +// reject article and don't ask again (CHECK command) +const RPL_StreamingReject = "438" + +// article transfer via streaming failed (TAKETHIS) +const RPL_StreamingFailed = "439" + +// posting not permitted (1st stage of POST command) +const RPL_PostingNotPermitted = "440" + +// posting failed (2nd stage of POST command) +const RPL_PostingFailed = "441" + +// authorization required +const RPL_AuthorizeRequired = "450" + +// authorization rejected +const RPL_AuthorizeRejected = "452" + +// command unavaibale until client has authenticated +const RPL_AuthenticateRequired = "480" + +// authentication creds rejected +const RPL_AuthenticateRejected = "482" + +// command unavailable until connection is encrypted +const RPL_EncryptionRequired = "483" + +// 5xx codes + +// got an unknown command +const RPL_UnknownCommand = "500" + +// got a command with invalid syntax +const RPL_SyntaxError = "501" + +// fatal error happened and connection will close +const RPL_GenericFatal = "502" + +// feature is not supported +const RPL_FeatureNotSupported = "503" + +// message encoding is bad +const RPL_EncodingError = "504" + +// starttls can not be done +const RPL_TLSRejected = "580" + +// line sent on invalid mode +const Line_InvalidMode = RPL_SyntaxError + " Invalid Mode Selected" + +// line sent on successful streaming +const Line_StreamingAllowed = RPL_PostingStreaming + " aw yeh streamit brah" + +// send this when we handle a QUIT command +const Line_RPLQuit = RPL_Quit + " bai" diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/nntp/commands.go b/contrib/backends/nntpchand/src/nntpchan/lib/nntp/commands.go new file mode 100644 index 0000000..2d344c4 --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/nntp/commands.go @@ -0,0 +1,27 @@ +package nntp + +type Command string + +func (c Command) String() string { + return string(c) +} + +// command to list newsgroups +const CMD_Newsgroups = Command("NEWSGROUPS 0 0 GMT") + +// create group command for a newsgroup +func CMD_Group(g Newsgroup) Command { + return Command("GROUP " + g.String()) +} + +const CMD_XOver = Command("XOVER 0") + +func CMD_Article(msgid MessageID) Command { + return Command("ARTICLE " + msgid.String()) +} + +func CMD_Head(msgid MessageID) Command { + return Command("HEAD " + msgid.String()) +} + +const CMD_Capabilities = Command("CAPABILITIES") diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/nntp/common.go b/contrib/backends/nntpchand/src/nntpchan/lib/nntp/common.go new file mode 100644 index 0000000..9076e0e --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/nntp/common.go @@ -0,0 +1,75 @@ +package nntp + +import ( + "crypto/sha1" + "fmt" + "io" + "nntpchan/lib/crypto" + "regexp" + "strings" + "time" +) + +var exp_valid_message_id = regexp.MustCompilePOSIX(`^<[a-zA-Z0-9$.]{2,128}@[a-zA-Z0-9\-.]{2,63}>$`) + +type MessageID string + +// return true if this message id is well formed, otherwise return false +func (msgid MessageID) Valid() bool { + return exp_valid_message_id.Copy().MatchString(msgid.String()) +} + +// get message id as string +func (msgid MessageID) String() string { + return string(msgid) +} + +// compute long form hash of message id +func (msgid MessageID) LongHash() string { + return fmt.Sprintf("%x", sha1.Sum([]byte(msgid))) +} + +// compute truncated form of message id hash +func (msgid MessageID) ShortHash() string { + return strings.ToLower(msgid.LongHash()[:18]) +} + +// compute blake2 hash of message id +func (msgid MessageID) Blake2Hash() string { + h := crypto.Hash() + io.WriteString(h, msgid.String()) + return strings.ToLower(fmt.Sprintf("%x", h.Sum(nil))) +} + +// generate a new message id given name of server +func GenMessageID(name string) MessageID { + r := crypto.RandBytes(4) + t := time.Now() + return MessageID(fmt.Sprintf("<%x$%d@%s>", r, t.Unix(), name)) +} + +var exp_valid_newsgroup = regexp.MustCompilePOSIX(`^[a-zA-Z0-9.]{1,128}$`) + +// an nntp newsgroup +type Newsgroup string + +// return true if this newsgroup is well formed otherwise false +func (g Newsgroup) Valid() bool { + return exp_valid_newsgroup.Copy().MatchString(g.String()) +} + +// get newsgroup as string +func (g Newsgroup) String() string { + return string(g) +} + +// (message-id, newsgroup) tuple +type ArticleEntry [2]string + +func (e ArticleEntry) MessageID() MessageID { + return MessageID(e[0]) +} + +func (e ArticleEntry) Newsgroup() Newsgroup { + return Newsgroup(e[1]) +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/nntp/common_test.go b/contrib/backends/nntpchand/src/nntpchan/lib/nntp/common_test.go new file mode 100644 index 0000000..607af9b --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/nntp/common_test.go @@ -0,0 +1,44 @@ +package nntp + +import ( + "testing" +) + +func TestGenMessageID(t *testing.T) { + msgid := GenMessageID("test.tld") + t.Logf("generated id %s", msgid) + if !msgid.Valid() { + t.Logf("invalid generated message-id %s", msgid) + t.Fail() + } + msgid = GenMessageID("<><><>") + t.Logf("generated id %s", msgid) + if msgid.Valid() { + t.Logf("generated valid message-id when it should've been invalid %s", msgid) + t.Fail() + } +} + +func TestMessageIDHash(t *testing.T) { + msgid := GenMessageID("test.tld") + lh := msgid.LongHash() + sh := msgid.ShortHash() + bh := msgid.Blake2Hash() + t.Logf("long=%s short=%s blake2=%s", lh, sh, bh) +} + +func TestValidNewsgroup(t *testing.T) { + g := Newsgroup("overchan.test") + if !g.Valid() { + t.Logf("%s is invalid?", g) + t.Fail() + } +} + +func TestInvalidNewsgroup(t *testing.T) { + g := Newsgroup("asd.asd.asd.&&&") + if g.Valid() { + t.Logf("%s should be invalid", g) + t.Fail() + } +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/nntp/conn.go b/contrib/backends/nntpchand/src/nntpchan/lib/nntp/conn.go new file mode 100644 index 0000000..39cd91f --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/nntp/conn.go @@ -0,0 +1,53 @@ +package nntp + +// an nntp connection +type Conn interface { + + // negotiate an nntp session on this connection + // returns nil if we negitated successfully + // returns ErrAuthRejected if the remote server rejected any authentication + // we sent or another error if one occured while negotiating + Negotiate(stream bool) error + + // obtain connection state + GetState() *ConnState + + // retutrn true if posting is allowed + // return false if posting is not allowed + PostingAllowed() bool + + // handle inbound non-streaming connection + // call event hooks on event + ProcessInbound(hooks EventHooks) + + // does this connection want to do nntp streaming? + WantsStreaming() bool + + // what mode are we in? + // returns mode in all caps + Mode() Mode + + // initiate nntp streaming + // after calling this the caller MUST call StreamAndQuit() + // returns a channel for message ids, true if caller sends on the channel or + // returns nil and ErrStreamingNotAllowed if streaming is not allowed on this + // connection or another error if one occurs while trying to start streaming + StartStreaming() (chan ArticleEntry, error) + + // stream articles and quit when the channel obtained by StartStreaming() is + // closed, after which this nntp connection is no longer open + StreamAndQuit() + + // is this nntp connection open? + IsOpen() bool + + // send quit command and close connection + Quit() + + // download all articles in a newsgroup + // returns error if a network error occurs + DownloadGroup(g Newsgroup) error + + // get list of active newsgroups + ListNewsgroups() ([]Newsgroup, error) +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/nntp/conn_v1.go b/contrib/backends/nntpchand/src/nntpchan/lib/nntp/conn_v1.go new file mode 100644 index 0000000..c10181c --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/nntp/conn_v1.go @@ -0,0 +1,1478 @@ +package nntp + +import ( + "bufio" + "bytes" + "crypto/tls" + "encoding/base64" + "encoding/json" + "errors" + "fmt" + log "github.com/Sirupsen/logrus" + "io" + "mime" + "mime/multipart" + "net" + "net/textproto" + "nntpchan/lib/config" + "nntpchan/lib/nntp/message" + "nntpchan/lib/store" + "nntpchan/lib/util" + "os" + "strings" +) + +// handles 1 line of input from a connection +type lineHandlerFunc func(c *v1Conn, line string, hooks EventHooks) error + +// base nntp connection +type v1Conn struct { + // buffered connection + C *textproto.Conn + + // unexported fields ... + + // connection state (mutable) + state ConnState + // tls connection if tls is established + tlsConn *tls.Conn + // tls config for this connection, nil if we don't support tls + tlsConfig *tls.Config + // has this connection authenticated yet? + authenticated bool + // the username logged in with if it has authenticated via user/pass + username string + // underlying network socket + conn net.Conn + // server's name + serverName string + // article acceptor checks if we want articles + acceptor ArticleAcceptor + // headerIO for read/write of article header + hdrio *message.HeaderIO + // article storage + storage store.Storage + // event callbacks + hooks EventHooks + // inbound connection authenticator + auth ServerAuth + // command handlers + cmds map[string]lineHandlerFunc +} + +// json representation of this connection +// format is: +// { +// "state" : (connection state object), +// "authed" : bool, +// "tls" : (tls info or null if plaintext connection) +// } +func (c *v1Conn) MarshalJSON() ([]byte, error) { + j := make(map[string]interface{}) + j["state"] = c.state + j["authed"] = c.authenticated + if c.tlsConn == nil { + j["tls"] = nil + } else { + j["tls"] = c.tlsConn.ConnectionState() + } + return json.Marshal(j) +} + +// get the current state of our connection (immutable) +func (c *v1Conn) GetState() (state *ConnState) { + return &ConnState{ + FeedName: c.state.FeedName, + ConnName: c.state.ConnName, + HostName: c.state.HostName, + Mode: c.state.Mode, + Group: c.state.Group, + Article: c.state.Article, + Policy: &FeedPolicy{ + Whitelist: c.state.Policy.Whitelist, + Blacklist: c.state.Policy.Blacklist, + AllowAnonPosts: c.state.Policy.AllowAnonPosts, + AllowAnonAttachments: c.state.Policy.AllowAnonAttachments, + AllowAttachments: c.state.Policy.AllowAttachments, + UntrustedRequiresPoW: c.state.Policy.UntrustedRequiresPoW, + }, + } +} + +func (c *v1Conn) Group() string { + return c.state.Group.String() +} + +func (c *v1Conn) IsOpen() bool { + return c.state.Open +} + +func (c *v1Conn) Mode() Mode { + return c.state.Mode +} + +// is posting allowed rignt now? +func (c *v1Conn) PostingAllowed() bool { + return c.Authed() +} + +// process incoming commands +// call event hooks as needed +func (c *v1Conn) Process(hooks EventHooks) { + var err error + var line string + for err == nil { + line, err = c.readline() + if len(line) == 0 { + // eof (proably?) + c.Close() + return + } + + uline := strings.ToUpper(line) + parts := strings.Split(uline, " ") + handler, ok := c.cmds[parts[0]] + if ok { + // we know the command + err = handler(c, line, hooks) + } else { + // we don't know the command + err = c.printfLine("%s Unknown Command: %s", RPL_UnknownCommand, line) + } + } +} + +type v1OBConn struct { + C v1Conn + supports_stream bool + streamChnl chan ArticleEntry + conf *config.FeedConfig +} + +func (c *v1OBConn) IsOpen() bool { + return c.IsOpen() +} + +func (c *v1OBConn) Mode() Mode { + return c.Mode() +} + +func (c *v1OBConn) DownloadGroup(g Newsgroup) (err error) { + err = c.C.printfLine(CMD_Group(g).String()) + if err == nil { + var line string + line, err = c.C.readline() + if strings.HasPrefix(line, RPL_NoSuchGroup) { + // group does not exist + // don't error this is not a network io error + return + } + // send XOVER + err = c.C.printfLine(CMD_XOver.String()) + if err == nil { + line, err = c.C.readline() + if err == nil { + if !strings.HasPrefix(line, RPL_Overview) { + // bad response + // not a network io error, don't error + return + } + var msgids []MessageID + // read reply + for err == nil && line != "." { + line, err = c.C.readline() + parts := strings.Split(line, "\t") + if len(parts) != 6 { + // incorrect size + continue + } + m := MessageID(parts[4]) + r := MessageID(parts[5]) + if c.C.acceptor == nil { + // no acceptor take it if store doesn't have it + if c.C.storage.HasArticle(m.String()) == store.ErrNoSuchArticle { + msgids = append(msgids, m) + } + } else { + // check if thread is banned + if c.C.acceptor.CheckMessageID(r).Ban() { + continue + } + // check if message is wanted + if c.C.acceptor.CheckMessageID(m).Accept() { + msgids = append(msgids, m) + } + } + } + var accepted []MessageID + + for _, msgid := range msgids { + + if err != nil { + return // io error + } + + if !msgid.Valid() { + // invalid message id + continue + } + // get message header + err = c.C.printfLine(CMD_Head(msgid).String()) + if err == nil { + line, err = c.C.readline() + if err == nil { + if !strings.HasPrefix(line, RPL_ArticleHeaders) { + // bad response + continue + } + // read message header + dr := c.C.C.DotReader() + var hdr message.Header + hdr, err = c.C.hdrio.ReadHeader(dr) + if err == nil { + if c.C.acceptor == nil { + accepted = append(accepted, msgid) + } else if c.C.acceptor.CheckHeader(hdr).Accept() { + accepted = append(accepted, msgid) + } + } + } + } + } + // download wanted messages + for _, msgid := range accepted { + if err != nil { + // io error + return + } + // request message + err = c.C.printfLine(CMD_Article(msgid).String()) + if err == nil { + line, err = c.C.readline() + if err == nil { + if !strings.HasPrefix(line, RPL_Article) { + // bad response + continue + } + // read article + _, err = c.C.readArticle(false, c.C.hooks) + if err == nil { + // we read it okay + } + } + } + } + } + } + } + return +} + +func (c *v1OBConn) ListNewsgroups() (groups []Newsgroup, err error) { + err = c.C.printfLine(CMD_Newsgroups.String()) + if err == nil { + var line string + line, err = c.C.readline() + if err == nil { + if !strings.HasPrefix(line, RPL_NewsgroupList) { + // bad stuff + err = errors.New("invalid reply for NEWSGROUPS command: " + line) + return + } + for err == nil && line != "." { + line, err = c.C.readline() + if err == nil { + parts := strings.Split(line, " ") + if len(parts) != 4 { + // bad format + continue + } + groups = append(groups, Newsgroup(parts[0])) + } + } + } + } + return +} + +// negioate outbound connection +func (c *v1OBConn) Negotiate(stream bool) (err error) { + var line string + // discard first line + _, err = c.C.readline() + if err == nil { + // request capabilities + err = c.C.printfLine(CMD_Capabilities.String()) + dr := c.C.C.DotReader() + var b bytes.Buffer + _, err = io.Copy(&b, dr) + if err == nil { + // try login if specified + if c.conf.Username != "" && c.conf.Password != "" { + err = c.C.printfLine("AUTHINFO USER %s", c.conf.Username) + if err != nil { + return + } + line, err = c.C.readline() + if strings.HasPrefix(line, RPL_MoreAuth) { + err = c.C.printfLine("AUTHINFO PASS %s", c.conf.Password) + if err != nil { + return + } + line, err = c.C.readline() + if err != nil { + return + } + if strings.HasPrefix(line, RPL_AuthAccepted) { + log.WithFields(log.Fields{ + "name": c.conf.Name, + "user": c.conf.Username, + }).Info("authentication accepted") + } else { + // not accepted? + err = errors.New(line) + } + } else { + // bad user? + err = errors.New(line) + } + } + if err == nil { + if stream { + // set mode stream + err = c.C.printfLine(ModeStream.String()) + if err == nil { + line, err = c.C.readline() + if err == nil && !strings.HasPrefix(line, RPL_PostingStreaming) { + err = errors.New("streaiming not allowed") + } + } + } + } + } + } + return +} + +func (c *v1OBConn) PostingAllowed() bool { + return c.C.PostingAllowed() +} + +func (c *v1OBConn) ProcessInbound(hooks EventHooks) { + +} + +func (c *v1OBConn) WantsStreaming() bool { + return c.supports_stream +} + +func (c *v1OBConn) StreamAndQuit() { + for { + e, ok := <-c.streamChnl + if ok { + // do CHECK + msgid := e.MessageID() + if !msgid.Valid() { + log.WithFields(log.Fields{ + "pkg": "nntp-conn", + "state": c.C.state, + "msgid": msgid, + }).Warn("Dropping stream event with invalid message-id") + continue + } + // send line + err := c.C.printfLine("%s %s", stream_CHECK, msgid) + if err == nil { + // read response + var line string + line, err = c.C.readline() + ev := StreamEvent(line) + if ev.Valid() { + cmd := ev.Command() + if cmd == RPL_StreamingAccept { + // accepted to send + + // check if we really have it in storage + err = c.C.storage.HasArticle(msgid.String()) + if err == nil { + var r io.ReadCloser + r, err = c.C.storage.OpenArticle(msgid.String()) + if err == nil { + log.WithFields(log.Fields{ + "pkg": "nntp-conn", + "state": c.C.state, + "msgid": msgid, + }).Debug("article accepted will send via TAKETHIS now") + _ = c.C.printfLine("%s %s", stream_TAKETHIS, msgid) + br := bufio.NewReader(r) + n := int64(0) + for err == nil { + var line string + line, err = br.ReadString(10) + if err == io.EOF { + err = nil + break + } + line = strings.Trim(line, "\r") + line = strings.Trim(line, "\n") + err = c.C.printfLine(line) + n += int64(len(line)) + } + r.Close() + err = c.C.printfLine(".") + if err == nil { + // successful takethis sent + log.WithFields(log.Fields{ + "pkg": "nntp-conn", + "state": c.C.state, + "msgid": msgid, + "bytes": n, + }).Debug("article transfer done") + // read response + line, err = c.C.readline() + ev := StreamEvent(line) + if ev.Valid() { + // valid reply + cmd := ev.Command() + if cmd == RPL_StreamingTransfered { + // successful transfer + log.WithFields(log.Fields{ + "feed": c.C.state.FeedName, + "msgid": msgid, + "bytes": n, + }).Debug("Article Transferred") + // call hooks + if c.C.hooks != nil { + c.C.hooks.SentArticleVia(msgid, c.C.state.FeedName) + } + } else { + // failed transfer + log.WithFields(log.Fields{ + "feed": c.C.state.FeedName, + "msgid": msgid, + "bytes": n, + }).Debug("Article Rejected") + } + } + } else { + log.WithFields(log.Fields{ + "feed": c.C.state.FeedName, + "msgid": msgid, + }).Errorf("failed to transfer: %s", err.Error()) + } + } + } else { + log.WithFields(log.Fields{ + "pkg": "nntp-conn", + "state": c.C.state, + "msgid": msgid, + }).Warn("article not in storage, not sending") + } + } + } else { + // invalid reply + log.WithFields(log.Fields{ + "pkg": "nntp-conn", + "state": c.C.state, + "msgid": msgid, + "line": line, + }).Error("invalid streaming response") + // close + return + } + } else { + log.WithFields(log.Fields{ + "pkg": "nntp-conn", + "state": c.C.state, + "msgid": msgid, + }).Error("streaming error during CHECK", err) + return + } + } else { + // channel closed + return + } + } +} + +func (c *v1OBConn) Quit() { + c.C.printfLine("QUIT yo") + c.C.readline() + c.C.Close() +} + +func (c *v1OBConn) StartStreaming() (chnl chan ArticleEntry, err error) { + if c.streamChnl == nil { + c.streamChnl = make(chan ArticleEntry) + + } + chnl = c.streamChnl + return +} + +func (c *v1OBConn) GetState() *ConnState { + return c.GetState() +} + +// create a new connection from an established connection +func newOutboundConn(c net.Conn, s *Server, conf *config.FeedConfig) Conn { + + sname := s.Name() + + if len(sname) == 0 { + sname = "nntp.anon.tld" + } + storage := s.Storage + if storage == nil { + storage = store.NewNullStorage() + } + return &v1OBConn{ + conf: conf, + C: v1Conn{ + hooks: s, + state: ConnState{ + FeedName: conf.Name, + HostName: conf.Addr, + Open: true, + }, + serverName: sname, + storage: storage, + C: textproto.NewConn(c), + conn: c, + hdrio: message.NewHeaderIO(), + }, + } +} + +type v1IBConn struct { + C v1Conn +} + +func (c *v1IBConn) DownloadGroup(g Newsgroup) error { + return nil +} + +func (c *v1IBConn) ListNewsgroups() (groups []Newsgroup, err error) { + return +} + +func (c *v1IBConn) GetState() *ConnState { + return c.C.GetState() +} + +// negotiate an inbound connection +func (c *v1IBConn) Negotiate(stream bool) (err error) { + var line string + if c.PostingAllowed() { + line = Line_PostingAllowed + } else { + line = Line_PostingNotAllowed + } + err = c.C.printfLine(line) + return +} + +func (c *v1IBConn) PostingAllowed() bool { + return c.C.PostingAllowed() +} + +func (c *v1IBConn) IsOpen() bool { + return c.C.IsOpen() +} + +func (c *v1IBConn) Quit() { + // inbound connections quit without warning + log.WithFields(log.Fields{ + "pkg": "nntp-ibconn", + "addr": c.C.conn.RemoteAddr(), + }).Info("closing inbound connection") + c.C.Close() +} + +// is this connection authenticated? +func (c *v1Conn) Authed() bool { + return c.tlsConn != nil || c.authenticated +} + +// unconditionally close connection +func (c *v1Conn) Close() { + if c.tlsConn == nil { + // tls is not on + c.C.Close() + } else { + // tls is on + // we should close tls cleanly + c.tlsConn.Close() + } + c.state.Open = false +} + +func (c *v1IBConn) WantsStreaming() bool { + return c.C.state.Mode.Is(MODE_STREAM) +} + +func (c *v1Conn) printfLine(format string, args ...interface{}) error { + log.WithFields(log.Fields{ + "pkg": "nntp-conn", + "version": 1, + "state": &c.state, + "io": "send", + }).Debugf(format, args...) + return c.C.PrintfLine(format, args...) +} + +func (c *v1Conn) readline() (line string, err error) { + line, err = c.C.ReadLine() + log.WithFields(log.Fields{ + "pkg": "nntp-conn", + "version": 1, + "state": &c.state, + "io": "recv", + }).Debug(line) + return +} + +// handle switching nntp modes for inbound connection +func switchModeInbound(c *v1Conn, line string, hooks EventHooks) (err error) { + cmd := ModeCommand(line) + m := c.Mode() + if cmd.Is(ModeReader) { + if m.Is(MODE_STREAM) { + // we need to stop streaming + } + var line string + if c.PostingAllowed() { + line = Line_PostingAllowed + } else { + line = Line_PostingNotAllowed + } + err = c.printfLine(line) + if err == nil { + c.state.Mode = MODE_READER + } + } else if cmd.Is(ModeStream) { + // we want to switch to streaming mode + err = c.printfLine(Line_StreamingAllowed) + if err == nil { + c.state.Mode = MODE_STREAM + } + } else { + err = c.printfLine(Line_InvalidMode) + } + return +} + +// handle quit command +func quitConnection(c *v1Conn, line string, hooks EventHooks) (err error) { + log.WithFields(log.Fields{ + "pkg": "nntp-conn", + "version": "1", + "state": &c.state, + }).Debug("quit requested") + err = c.printfLine(Line_RPLQuit) + c.Close() + return +} + +// send our capabailities +func sendCapabilities(c *v1Conn, line string, hooks EventHooks) (err error) { + var caps []string + + caps = append(caps, "MODE-READER", "IMPLEMENTATION nntpchand", "STREAMING") + if c.tlsConfig != nil { + caps = append(caps, "STARTTLS") + } + + err = c.printfLine("%s We can do things", RPL_Capabilities) + if err == nil { + for _, l := range caps { + err = c.printfLine(l) + if err != nil { + log.WithFields(log.Fields{ + "pkg": "nntp-conn", + "version": "1", + "state": &c.state, + }).Error(err) + } + } + err = c.printfLine(".") + } + return +} + +// read an article via dotreader +func (c *v1Conn) readArticle(newpost bool, hooks EventHooks) (ps PolicyStatus, err error) { + store_r, store_w := io.Pipe() + article_r, article_w := io.Pipe() + article_body_r, article_body_w := io.Pipe() + + accept_chnl := make(chan PolicyStatus) + store_info_chnl := make(chan ArticleEntry) + store_result_chnl := make(chan error) + + hdr_chnl := make(chan message.Header) + + log.WithFields(log.Fields{ + "pkg": "nntp-conn", + }).Debug("start reading") + done_chnl := make(chan PolicyStatus) + go func() { + var err error + dr := c.C.DotReader() + var buff [1024]byte + var n int64 + n, err = io.CopyBuffer(article_w, dr, buff[:]) + log.WithFields(log.Fields{ + "n": n, + }).Debug("read from connection") + if err != nil && err != io.EOF { + article_w.CloseWithError(err) + } else { + article_w.Close() + } + st := <-accept_chnl + close(accept_chnl) + // get result from storage + err2, ok := <-store_result_chnl + if ok && err2 != io.EOF { + err = err2 + } + close(store_result_chnl) + done_chnl <- st + }() + + // parse message and store attachments in bg + go func(msgbody io.ReadCloser) { + defer msgbody.Close() + hdr, ok := <-hdr_chnl + if !ok { + return + } + // all text in this post + // txt := new(bytes.Buffer) + // the article itself + // a := new(model.Article) + var err error + if hdr.IsMultipart() { + var params map[string]string + _, params, err = hdr.GetMediaType() + if err == nil { + boundary, ok := params["boundary"] + if ok { + part_r := multipart.NewReader(msgbody, boundary) + for err == nil { + var part *multipart.Part + part, err = part_r.NextPart() + if err == io.EOF { + // we done + break + } else if err == nil { + // we gots a part + + // get header + part_hdr := part.Header + + // check for base64 encoding + var part_body io.Reader + if part_hdr.Get("Content-Transfer-Encoding") == "base64" { + part_body = base64.NewDecoder(base64.StdEncoding, part) + } else { + part_body = part + } + + // get content type + content_type := part_hdr.Get("Content-Type") + if len(content_type) == 0 { + // assume text/plain + content_type = "text/plain; charset=UTF8" + } + var part_type string + // extract mime type + part_type, _, err = mime.ParseMediaType(content_type) + if err == nil { + + if part_type == "text/plain" { + // if we are plaintext save it to the text buffer + _, err = io.Copy(util.Discard, part_body) + } else { + var fpath string + fname := part.FileName() + fpath, err = c.storage.StoreAttachment(part_body, fname) + if err == nil { + // stored attachment good + log.WithFields(log.Fields{ + "pkg": "nntp-conn", + "state": &c.state, + "version": "1", + "filename": fname, + "filepath": fpath, + }).Debug("attachment stored") + } else { + // failed to save attachment + log.WithFields(log.Fields{ + "pkg": "nntp-conn", + "state": &c.state, + "version": "1", + }).Error("failed to save attachment ", err) + } + } + } else { + // cannot read part header + log.WithFields(log.Fields{ + "pkg": "nntp-conn", + "state": &c.state, + "version": "1", + }).Error("bad attachment in multipart message ", err) + } + err = nil + part.Close() + } else if err != io.EOF { + // error reading part + log.WithFields(log.Fields{ + "pkg": "nntp-conn", + "state": &c.state, + "version": "1", + }).Error("error reading part ", err) + } + } + } + } + } else if hdr.IsSigned() { + // signed message + + // discard for now + _, err = io.Copy(util.Discard, msgbody) + } else { + // plaintext message + var n int64 + n, err = io.Copy(util.Discard, msgbody) + log.WithFields(log.Fields{ + "bytes": n, + "pkg": "nntp-conn", + }).Debug("text body copied") + } + if err != nil && err != io.EOF { + log.WithFields(log.Fields{ + "pkg": "nntp-conn", + "state": &c.state, + }).Error("error handing message body", err) + } + }(article_body_r) + + // store function + go func(r io.ReadCloser) { + e, ok := <-store_info_chnl + if !ok { + // failed to get info + // don't read anything + r.Close() + store_result_chnl <- io.EOF + return + } + msgid := e.MessageID() + if msgid.Valid() { + // valid message-id + log.WithFields(log.Fields{ + "pkg": "nntp-conn", + "msgid": msgid, + "version": "1", + "state": &c.state, + }).Debug("storing article") + + fpath, err := c.storage.StoreArticle(r, msgid.String(), e.Newsgroup().String()) + r.Close() + if err == nil { + log.WithFields(log.Fields{ + "pkg": "nntp-conn", + "msgid": msgid, + "version": "1", + "state": &c.state, + }).Debug("stored article okay to ", fpath) + // we got the article + if hooks != nil { + hooks.GotArticle(msgid, e.Newsgroup()) + } + store_result_chnl <- io.EOF + log.Debugf("store informed") + } else { + // error storing article + log.WithFields(log.Fields{ + "pkg": "nntp-conn", + "msgid": msgid, + "state": &c.state, + "version": "1", + }).Error("failed to store article ", err) + io.Copy(util.Discard, r) + store_result_chnl <- err + } + } else { + // invalid message-id + // discard + log.WithFields(log.Fields{ + "pkg": "nntp-conn", + "msgid": msgid, + "state": &c.state, + "version": "1", + }).Warn("store will discard message with invalid message-id") + io.Copy(util.Discard, r) + store_result_chnl <- nil + r.Close() + } + }(store_r) + + // acceptor function + go func(r io.ReadCloser, out_w, body_w io.WriteCloser) { + var w io.WriteCloser + defer r.Close() + status := PolicyAccept + hdr, err := c.hdrio.ReadHeader(r) + if err == nil { + // append path + hdr.AppendPath(c.serverName) + // get message-id + var msgid MessageID + if newpost { + // new post + // generate it + msgid = GenMessageID(c.serverName) + hdr.Set("Message-ID", msgid.String()) + } else { + // not a new post, get from header + msgid = MessageID(hdr.MessageID()) + if msgid.Valid() { + // check store fo existing article + err = c.storage.HasArticle(msgid.String()) + if err == store.ErrNoSuchArticle { + // we don't have the article + status = PolicyAccept + log.Infof("accept article %s", msgid) + } else if err == nil { + // we do have the article, reject it we don't need it again + status = PolicyReject + } else { + // some other error happened + log.WithFields(log.Fields{ + "pkg": "nntp-conn", + "state": c.state, + }).Error("failed to check store for article ", err) + } + err = nil + } else { + // bad article + status = PolicyBan + } + } + // check the header if we have an acceptor and the previous checks are good + if status.Accept() && c.acceptor != nil { + status = c.acceptor.CheckHeader(hdr) + } + if status.Accept() { + // we have accepted the article + // store to disk + w = out_w + } else { + // we have not accepted the article + // discard + w = util.Discard + out_w.Close() + } + store_info_chnl <- ArticleEntry{msgid.String(), hdr.Newsgroup()} + hdr_chnl <- hdr + // close the channel for headers + close(hdr_chnl) + // write header out to storage + err = c.hdrio.WriteHeader(hdr, w) + if err == nil { + mw := io.MultiWriter(body_w, w) + // we wrote header + var n int64 + if c.acceptor == nil { + // write the rest of the body + // we don't care about article size + log.WithFields(log.Fields{}).Debug("copying body") + var buff [128]byte + n, err = io.CopyBuffer(mw, r, buff[:]) + } else { + // we care about the article size + max := c.acceptor.MaxArticleSize() + var n int64 + // copy it out + n, err = io.CopyN(mw, r, max) + if err == nil { + if n < max { + // under size limit + // we gud + log.WithFields(log.Fields{ + "pkg": "nntp-conn", + "bytes": n, + "state": &c.state, + }).Debug("body fits") + } else { + // too big, discard the rest + _, err = io.Copy(util.Discard, r) + // ... and ban it + status = PolicyBan + } + } + } + log.WithFields(log.Fields{ + "pkg": "nntp-conn", + "bytes": n, + "state": &c.state, + }).Debug("body wrote") + // TODO: inform store to delete article and attachments + } else { + // error writing header + log.WithFields(log.Fields{ + "msgid": msgid, + }).Error("error writing header ", err) + } + } else { + // error reading header + // possibly a read error? + status = PolicyDefer + } + // close info channel for store + close(store_info_chnl) + w.Close() + // close body pipe + body_w.Close() + // inform result + log.Debugf("status %s", status) + accept_chnl <- status + log.Debugf("informed") + }(article_r, store_w, article_body_w) + + ps = <-done_chnl + close(done_chnl) + log.Debug("read article done") + return +} + +// handle IHAVE command +func nntpRecvArticle(c *v1Conn, line string, hooks EventHooks) (err error) { + parts := strings.Split(line, " ") + if len(parts) == 2 { + msgid := MessageID(parts[1]) + if msgid.Valid() { + // valid message-id + err = c.printfLine("%s send article to be transfered", RPL_TransferAccepted) + // read in article + if err == nil { + var status PolicyStatus + status, err = c.readArticle(false, hooks) + if err == nil { + // we read in article + if status.Accept() { + // accepted + err = c.printfLine("%s transfer wuz gud", RPL_TransferOkay) + } else if status.Defer() { + // deferred + err = c.printfLine("%s transfer defer", RPL_TransferDefer) + } else if status.Reject() { + // rejected + err = c.printfLine("%s transfer rejected, don't send it again brah", RPL_TransferReject) + } + } else { + // could not transfer article + err = c.printfLine("%s transfer failed; try again later", RPL_TransferDefer) + } + } + } else { + // invalid message-id + err = c.printfLine("%s article not wanted", RPL_TransferNotWanted) + } + } else { + // invaldi syntax + err = c.printfLine("%s invalid syntax", RPL_SyntaxError) + } + return +} + +// handle POST command +func nntpPostArticle(c *v1Conn, line string, hooks EventHooks) (err error) { + if c.PostingAllowed() { + if c.Mode().Is(MODE_READER) { + err = c.printfLine("%s go ahead yo", RPL_PostAccepted) + var status PolicyStatus + status, err = c.readArticle(true, hooks) + if err == nil { + // read okay + if status.Accept() { + err = c.printfLine("%s post was recieved", RPL_PostReceived) + } else { + err = c.printfLine("%s posting failed", RPL_PostingFailed) + } + } else { + log.WithFields(log.Fields{ + "pkg": "nntp-conn", + "state": &c.state, + "version": "1", + }).Error("POST failed ", err) + err = c.printfLine("%s post failed: %s", RPL_PostingFailed, err) + } + } else { + // not in reader mode + err = c.printfLine("%s not in reader mode", RPL_WrongMode) + } + } else { + err = c.printfLine("%s posting is disallowed", RPL_PostingNotPermitted) + } + return +} + +// handle streaming line +func streamingLine(c *v1Conn, line string, hooks EventHooks) (err error) { + ev := StreamEvent(line) + if c.Mode().Is(MODE_STREAM) { + if ev.Valid() { + // valid stream line + cmd := ev.Command() + msgid := ev.MessageID() + if cmd == stream_CHECK { + if c.acceptor == nil { + // no acceptor, we'll take them all + err = c.printfLine("%s %s", RPL_StreamingAccept, msgid) + } else { + status := PolicyAccept + if c.storage.HasArticle(msgid.String()) == nil { + // we have this article + status = PolicyReject + } + if status.Accept() && c.acceptor != nil { + status = c.acceptor.CheckMessageID(ev.MessageID()) + } + if status.Accept() { + // accepted + err = c.printfLine("%s %s", RPL_StreamingAccept, msgid) + } else if status.Defer() { + // deferred + err = c.printfLine("%s %s", RPL_StreamingDefer, msgid) + } else { + // rejected + err = c.printfLine("%s %s", RPL_StreamingReject, msgid) + } + } + } else if cmd == stream_TAKETHIS { + var status PolicyStatus + status, err = c.readArticle(false, hooks) + if status.Accept() { + // this article was accepted + err = c.printfLine("%s %s", RPL_StreamingTransfered, msgid) + } else { + // this article was not accepted + err = c.printfLine("%s %s", RPL_StreamingReject, msgid) + } + } + } else { + // invalid line + err = c.printfLine("%s Invalid syntax", RPL_SyntaxError) + } + } else { + if ev.MessageID().Valid() { + // not in streaming mode + err = c.printfLine("%s %s", RPL_StreamingDefer, ev.MessageID()) + } else { + // invalid message id + err = c.printfLine("%s Invalid Syntax", RPL_SyntaxError) + } + } + return +} + +func newsgroupList(c *v1Conn, line string, hooks EventHooks, rpl string) (err error) { + var groups []string + if c.storage == nil { + // no database driver available + // let's say we carry overchan.test for now + groups = append(groups, "overchan.test") + } else { + groups, err = c.storage.GetAllNewsgroups() + } + + if err == nil { + // we got newsgroups from the db + dw := c.C.DotWriter() + fmt.Fprintf(dw, "%s list of newsgroups follows\n", rpl) + for _, g := range groups { + hi := uint64(1) + lo := uint64(0) + if c.storage != nil { + hi, lo, err = c.storage.GetWatermark(g) + } + if err != nil { + // log error if it occurs + log.WithFields(log.Fields{ + "pkg": "nntp-conn", + "group": g, + "state": c.state, + }).Warn("cannot get high low water marks for LIST command") + + } else { + fmt.Fprintf(dw, "%s %d %d y", g, hi, lo) + } + } + // flush dotwriter + err = dw.Close() + } else { + // db error while getting newsgroup list + err = c.printfLine("%s cannot list newsgroups %s", RPL_GenericError, err.Error()) + } + return +} + +// handle inbound STARTTLS command +func upgradeTLS(c *v1Conn, line string, hooks EventHooks) (err error) { + if c.tlsConfig == nil { + err = c.printfLine("%s TLS not supported", RPL_TLSRejected) + } else { + err = c.printfLine("%s Continue with TLS Negotiation", RPL_TLSContinue) + if err == nil { + tconn := tls.Server(c.conn, c.tlsConfig) + err = tconn.Handshake() + if err == nil { + // successful tls handshake + c.tlsConn = tconn + c.C = textproto.NewConn(c.tlsConn) + } else { + // tls failed + log.WithFields(log.Fields{ + "pkg": "nntp-conn", + "addr": c.conn.RemoteAddr(), + "state": c.state, + }).Warn("TLS Handshake failed ", err) + // fall back to plaintext + err = nil + } + } + } + return +} + +// switch to another newsgroup +func switchNewsgroup(c *v1Conn, line string, hooks EventHooks) (err error) { + parts := strings.Split(line, " ") + var has bool + var group Newsgroup + if len(parts) == 2 { + group = Newsgroup(parts[1]) + if group.Valid() { + // correct format + if c.storage == nil { + has = false + } else { + has, err = c.storage.HasNewsgroup(group.String()) + } + } + } + if has { + // we have it + hi := uint64(1) + lo := uint64(0) + if c.storage != nil { + // check database for water marks + hi, lo, err = c.storage.GetWatermark(group.String()) + } + if err == nil { + // XXX: ensure hi > lo + err = c.printfLine("%s %d %d %d %s", RPL_Group, hi-lo, lo, hi, group.String()) + if err == nil { + // line was sent + c.state.Group = group + log.WithFields(log.Fields{ + "pkg": "nntp-conn", + "group": group, + "state": c.state, + }).Debug("switched newsgroups") + } + } else { + err = c.printfLine("%s error checking for newsgroup %s", RPL_GenericError, err.Error()) + } + } else if err != nil { + // error + err = c.printfLine("%s error checking for newsgroup %s", RPL_GenericError, err.Error()) + } else { + // incorrect format + err = c.printfLine("%s no such newsgroup", RPL_NoSuchGroup) + } + return +} + +func handleAuthInfo(c *v1Conn, line string, hooks EventHooks) (err error) { + subcmd := line[9:] + if strings.HasPrefix(strings.ToUpper(subcmd), "USER") { + c.username = subcmd[5:] + err = c.printfLine("%s password required", RPL_MoreAuth) + } else if strings.HasPrefix(strings.ToUpper(subcmd), "PASS") { + var success bool + if c.username == "" { + // out of order commands + c.printfLine("%s auth info sent out of order yo", RPL_GenericError) + return + } else if c.auth == nil { + // no auth mechanism, this will be set to true if anon nntp is enabled + success = c.authenticated + } else { + // check login + success, err = c.auth.CheckLogin(c.username, subcmd[5:]) + } + if success { + // login good + err = c.printfLine("%s login gud, proceed yo", RPL_AuthAccepted) + c.authenticated = true + } else if err == nil { + // login bad + err = c.printfLine("%s bad login", RPL_AuthenticateRejected) + } else { + // error + err = c.printfLine("%s error processing login: %s", RPL_GenericError, err.Error()) + } + } else { + err = c.printfLine("%s only USER/PASS accepted with AUTHINFO", RPL_SyntaxError) + } + return +} + +func handleXOVER(c *v1Conn, line string, hooks EventHooks) (err error) { + group := c.Group() + if group == "" { + err = c.printfLine("%s no group selected", RPL_NoGroupSelected) + return + } + if !Newsgroup(group).Valid() { + err = c.printfLine("%s Invalid Newsgroup format", RPL_GenericError) + return + } + err = c.printfLine("%s overview follows", RPL_Overview) + if err != nil { + return + } + chnl := make(chan string) + go func() { + c.storage.ForEachInGroup(group, chnl) + close(chnl) + }() + i := 0 + for err == nil { + m, ok := <-chnl + if !ok { + break + } + msgid := MessageID(m) + if !msgid.Valid() { + continue + } + var f *os.File + f, err = c.storage.OpenArticle(m) + if f != nil { + h, e := c.hdrio.ReadHeader(f) + f.Close() + if e == nil { + i++ + err = c.printfLine("%.6d\t%s\t%s\t%s\t%s\t%s", i, h.Get("Subject", "None"), h.Get("From", "anon "), h.Get("Date", "???"), h.MessageID(), h.Reference()) + } + } + } + if err == nil { + err = c.printfLine(".") + } + return +} + +func handleArticle(c *v1Conn, line string, hooks EventHooks) (err error) { + msgid := MessageID(line[8:]) + if msgid.Valid() && c.storage.HasArticle(msgid.String()) == nil { + // valid id and we have it + var r io.ReadCloser + var buff [1024]byte + r, err = c.storage.OpenArticle(msgid.String()) + if err == nil { + err = c.printfLine("%s %s", RPL_Article, msgid) + for err == nil { + _, err = io.CopyBuffer(c.C.W, r, buff[:]) + } + if err == io.EOF { + err = nil + } + if err == nil { + err = c.printfLine(".") + } + r.Close() + return + } + } + // invalid id or we don't have it + err = c.printfLine("%s %s", RPL_NoArticleMsgID, msgid) + return +} + +// inbound streaming start +func (c *v1IBConn) StartStreaming() (chnl chan ArticleEntry, err error) { + if c.Mode().Is(MODE_STREAM) { + chnl = make(chan ArticleEntry) + } else { + err = ErrInvalidMode + } + return +} + +func (c *v1IBConn) Mode() Mode { + return c.C.Mode() +} + +func (c *v1IBConn) ProcessInbound(hooks EventHooks) { + c.C.Process(hooks) +} + +// inbound streaming handling +func (c *v1IBConn) StreamAndQuit() { +} + +func newInboundConn(s *Server, c net.Conn) Conn { + sname := s.Name() + storage := s.Storage + if storage == nil { + storage = store.NewNullStorage() + } + anon := false + if s.Config != nil { + anon = s.Config.AnonNNTP + } + return &v1IBConn{ + C: v1Conn{ + state: ConnState{ + FeedName: "inbound-feed", + HostName: c.RemoteAddr().String(), + Open: true, + }, + auth: s.Auth, + authenticated: anon, + serverName: sname, + storage: storage, + acceptor: s.Acceptor, + hdrio: message.NewHeaderIO(), + C: textproto.NewConn(c), + conn: c, + cmds: map[string]lineHandlerFunc{ + "STARTTLS": upgradeTLS, + "IHAVE": nntpRecvArticle, + "POST": nntpPostArticle, + "MODE": switchModeInbound, + "QUIT": quitConnection, + "CAPABILITIES": sendCapabilities, + "CHECK": streamingLine, + "TAKETHIS": streamingLine, + "LIST": func(c *v1Conn, line string, h EventHooks) error { + return newsgroupList(c, line, h, RPL_List) + }, + "NEWSGROUPS": func(c *v1Conn, line string, h EventHooks) error { + return newsgroupList(c, line, h, RPL_NewsgroupList) + }, + "GROUP": switchNewsgroup, + "AUTHINFO": handleAuthInfo, + "XOVER": handleXOVER, + "ARTICLE": handleArticle, + }, + }, + } +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/nntp/dial.go b/contrib/backends/nntpchand/src/nntpchan/lib/nntp/dial.go new file mode 100644 index 0000000..50dec23 --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/nntp/dial.go @@ -0,0 +1,15 @@ +package nntp + +import ( + "crypto/tls" + "nntpchan/lib/network" +) + +// establishes an outbound nntp connection to a remote server +type Dialer interface { + // dial out with a dialer + // if cfg is not nil, try to establish a tls connection with STARTTLS + // returns a new nntp connection and nil on successful handshake and login + // returns nil and an error if an error happened + Dial(d network.Dialer, cfg *tls.Config) (*Conn, error) +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/nntp/doc.go b/contrib/backends/nntpchand/src/nntpchan/lib/nntp/doc.go new file mode 100644 index 0000000..99bfdcf --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/nntp/doc.go @@ -0,0 +1,4 @@ +// +// nntp client/server +// +package nntp diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/nntp/event_test.go b/contrib/backends/nntpchand/src/nntpchan/lib/nntp/event_test.go new file mode 100644 index 0000000..9e1d318 --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/nntp/event_test.go @@ -0,0 +1,60 @@ +package nntp + +import ( + "testing" +) + +func TestTAKETHISParse(t *testing.T) { + msgid := GenMessageID("test.tld") + ev := stream_cmd_TAKETHIS(msgid) + t.Logf("event: %s", ev) + if ev.MessageID() != msgid { + t.Logf("%s != %s, event was %s", msgid, ev.MessageID(), ev) + t.Fail() + } + if ev.Command() != "TAKETHIS" { + t.Logf("%s != TAKETHIS, event was %s", ev.Command(), ev) + t.Fail() + } + if !ev.Valid() { + t.Logf("%s is invalid stream event", ev) + t.Fail() + } +} + +func TestCHECKParse(t *testing.T) { + msgid := GenMessageID("test.tld") + ev := stream_cmd_CHECK(msgid) + t.Logf("event: %s", ev) + if ev.MessageID() != msgid { + t.Logf("%s != %s, event was %s", msgid, ev.MessageID(), ev) + t.Fail() + } + if ev.Command() != "CHECK" { + t.Logf("%s != CHECK, event was %s", ev.Command(), ev) + t.Fail() + } + if !ev.Valid() { + t.Logf("%s is invalid stream event", ev) + t.Fail() + } +} + +func TestInvalidStremEvent(t *testing.T) { + str := "asd" + ev := StreamEvent(str) + t.Logf("invalid str=%s ev=%s", str, ev) + if ev.Valid() { + t.Logf("invalid CHECK command is valid? %s", ev) + t.Fail() + } + + str = "asd asd" + ev = StreamEvent(str) + t.Logf("invalid str=%s ev=%s", str, ev) + + if ev.Valid() { + t.Logf("invalid CHECK command is valid? %s", ev) + t.Fail() + } +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/nntp/filter.go b/contrib/backends/nntpchand/src/nntpchan/lib/nntp/filter.go new file mode 100644 index 0000000..f24db95 --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/nntp/filter.go @@ -0,0 +1,19 @@ +package nntp + +import ( + "io" + "nntpchan/lib/nntp/message" +) + +// defines interface for filtering an nntp article +// filters can (and does) modify the article it operates on +type ArticleFilter interface { + // filter the article header + // returns the modified Header and an error if one occurs + FilterHeader(hdr message.Header) (message.Header, error) + + // reads the article's body and write the filtered version to an io.Writer + // returns the number of bytes written to the io.Writer, true if the body was + // modifed (or false if body is unchanged) and an error if one occurs + FilterAndWriteBody(body io.Reader, wr io.Writer) (int64, bool, error) +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/nntp/hook.go b/contrib/backends/nntpchand/src/nntpchan/lib/nntp/hook.go new file mode 100644 index 0000000..857009e --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/nntp/hook.go @@ -0,0 +1,30 @@ +package nntp + +import ( + log "github.com/Sirupsen/logrus" + "nntpchan/lib/config" + "os/exec" +) + +type Hook struct { + cfg *config.NNTPHookConfig +} + +func NewHook(cfg *config.NNTPHookConfig) *Hook { + return &Hook{ + cfg: cfg, + } +} + +func (h *Hook) GotArticle(msgid MessageID, group Newsgroup) { + c := exec.Command(h.cfg.Exec, group.String(), msgid.String()) + log.Infof("calling hook %s", h.cfg.Name) + err := c.Run() + if err != nil { + log.Errorf("error in nntp hook %s: %s", h.cfg.Name, err.Error()) + } +} + +func (*Hook) SentArticleVia(msgid MessageID, feedname string) { + +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/nntp/hooks.go b/contrib/backends/nntpchand/src/nntpchan/lib/nntp/hooks.go new file mode 100644 index 0000000..d1c18d4 --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/nntp/hooks.go @@ -0,0 +1,9 @@ +package nntp + +// callback hooks fired on certain events +type EventHooks interface { + // called when we have obtained an article given its message-id + GotArticle(msgid MessageID, group Newsgroup) + // called when we have sent an article to a single remote feed + SentArticleVia(msgid MessageID, feedname string) +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/nntp/message/article.go b/contrib/backends/nntpchand/src/nntpchan/lib/nntp/message/article.go new file mode 100644 index 0000000..c22a702 --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/nntp/message/article.go @@ -0,0 +1,11 @@ +package message + +// an nntp article +type Article struct { + + // the article's mime header + Header Header + + // unexported fields ... + +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/nntp/message/attachment.go b/contrib/backends/nntpchand/src/nntpchan/lib/nntp/message/attachment.go new file mode 100644 index 0000000..c98ab5b --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/nntp/message/attachment.go @@ -0,0 +1,16 @@ +package message + +import ( + "io" +) + +// attachment in an nntp article +type Attachment struct { + // mimetype + Mime string + // the filename + FileName string + // the fully decoded attachment body + // must close when done + Body io.ReadCloser +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/nntp/message/doc.go b/contrib/backends/nntpchand/src/nntpchan/lib/nntp/message/doc.go new file mode 100644 index 0000000..347d382 --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/nntp/message/doc.go @@ -0,0 +1,2 @@ +// package for parsing, packing, signing, verifying nntp articles +package message diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/nntp/message/header.go b/contrib/backends/nntpchand/src/nntpchan/lib/nntp/message/header.go new file mode 100644 index 0000000..7511fc1 --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/nntp/message/header.go @@ -0,0 +1,174 @@ +package message + +import ( + "io" + "mime" + "strings" +) + +// an nntp message header +type Header map[string][]string + +// get message-id header +func (self Header) MessageID() (v string) { + for _, hdr := range []string{"MessageID", "Message-ID", "Message-Id", "message-id"} { + v = self.Get(hdr, "") + if v != "" { + break + } + } + return +} + +func (self Header) Reference() (ref string) { + return self.Get("Reference", self.MessageID()) +} + +// extract media type from content-type header +func (self Header) GetMediaType() (mediatype string, params map[string]string, err error) { + return mime.ParseMediaType(self.Get("Content-Type", "text/plain")) +} + +// is this header for a multipart message? +func (self Header) IsMultipart() bool { + return strings.HasPrefix(self.Get("Content-Type", "text/plain"), "multipart/mixed") +} + +func (self Header) IsSigned() bool { + return self.Get("X-Pubkey-Ed25519", "") != "" +} + +func (self Header) Newsgroup() string { + return self.Get("Newsgroups", "overchan.discard") +} + +// do we have a key in this header? +func (self Header) Has(key string) bool { + _, ok := self[key] + return ok +} + +// set key value +func (self Header) Set(key, val string) { + self[key] = []string{val} +} + +func (self Header) AppendPath(name string) { + p := self.Get("Path", name) + if p != name { + p = name + "!" + p + } + self.Set("Path", p) +} + +// append value to key +func (self Header) Add(key, val string) { + if self.Has(key) { + self[key] = append(self[key], val) + } else { + self.Set(key, val) + } +} + +// get via key or return fallback value +func (self Header) Get(key, fallback string) string { + val, ok := self[key] + if ok { + str := "" + for _, k := range val { + str += k + ", " + } + return str[:len(str)-2] + } else { + return fallback + } +} + +// interface for types that can read an nntp header +type HeaderReader interface { + // blocking read an nntp header from an io.Reader + // return the read header and nil on success + // return nil and an error if an error occurred while reading + ReadHeader(r io.Reader) (Header, error) +} + +// interface for types that can write an nntp header +type HeaderWriter interface { + // blocking write an nntp header to an io.Writer + // returns an error if one occurs otherwise nil + WriteHeader(hdr Header, w io.Writer) error +} + +// implements HeaderReader and HeaderWriter +type HeaderIO struct { + delim byte +} + +// read header +func (s *HeaderIO) ReadHeader(r io.Reader) (hdr Header, err error) { + hdr = make(Header) + var k, v string + var buf [1]byte + for err == nil { + // read key + for err == nil { + _, err = r.Read(buf[:]) + if err != nil { + return + } + if buf[0] == 58 { // colin + // consume space + _, err = r.Read(buf[:]) + for err == nil { + _, err = r.Read(buf[:]) + if buf[0] == s.delim { + // got delimiter + hdr.Add(k, v) + k = "" + v = "" + break + } else { + v += string(buf[:]) + } + } + break + } else if buf[0] == s.delim { + // done + return + } else { + k += string(buf[:]) + } + } + } + return +} + +// write header +func (s *HeaderIO) WriteHeader(hdr Header, wr io.Writer) (err error) { + for k, vs := range hdr { + for _, v := range vs { + var line []byte + // key + line = append(line, []byte(k)...) + // ": " + line = append(line, 58, 32) + // value + line = append(line, []byte(v)...) + // delimiter + line = append(line, s.delim) + // write line + _, err = wr.Write(line) + if err != nil { + return + } + } + } + _, err = wr.Write([]byte{s.delim}) + return +} + +func NewHeaderIO() *HeaderIO { + return &HeaderIO{ + delim: 10, + } +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/nntp/mode.go b/contrib/backends/nntpchand/src/nntpchan/lib/nntp/mode.go new file mode 100644 index 0000000..11b30f5 --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/nntp/mode.go @@ -0,0 +1,69 @@ +package nntp + +import ( + "errors" + "strings" +) + +var ErrInvalidMode = errors.New("invalid mode set") + +// a mode set by an nntp client +type Mode string + +// reader mode +const MODE_READER = Mode("reader") + +// streaming mode +const MODE_STREAM = Mode("stream") + +// mode is not set +const MODE_UNSET = Mode("") + +// get as string +func (m Mode) String() string { + return strings.ToUpper(string(m)) +} + +// is this a valid mode of operation? +func (m Mode) Valid() bool { + return m.Is(MODE_READER) || m.Is(MODE_STREAM) +} + +// is this mode equal to another mode +func (m Mode) Is(other Mode) bool { + return m.String() == other.String() +} + +// a switch mode command +type ModeCommand string + +// get as string +func (m ModeCommand) String() string { + return strings.ToUpper(string(m)) +} + +// is this mode command well formed? +// does not check the actual mode sent. +func (m ModeCommand) Valid() bool { + s := m.String() + return strings.Count(s, " ") == 1 && strings.HasPrefix(s, "MODE ") +} + +// get the mode selected in this mode command +func (m ModeCommand) Mode() Mode { + return Mode(strings.Split(m.String(), " ")[1]) +} + +// check if this mode command is equal to an existing one +func (m ModeCommand) Is(cmd ModeCommand) bool { + return m.String() == cmd.String() +} + +// reader mode command +const ModeReader = ModeCommand("mode reader") + +// streaming mode command +const ModeStream = ModeCommand("mode stream") + +// line prefix for mode +const LinePrefix_Mode = "MODE " diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/nntp/multi.go b/contrib/backends/nntpchand/src/nntpchan/lib/nntp/multi.go new file mode 100644 index 0000000..e0480bc --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/nntp/multi.go @@ -0,0 +1,16 @@ +package nntp + +// multiplexed event hook +type MulitHook []EventHooks + +func (m MulitHook) GotArticle(msgid MessageID, group Newsgroup) { + for _, h := range m { + h.GotArticle(msgid, group) + } +} + +func (m MulitHook) SentArticleVia(msgid MessageID, feedname string) { + for _, h := range m { + h.SentArticleVia(msgid, feedname) + } +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/nntp/policy.go b/contrib/backends/nntpchand/src/nntpchan/lib/nntp/policy.go new file mode 100644 index 0000000..8ef0c5a --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/nntp/policy.go @@ -0,0 +1,29 @@ +package nntp + +// +// a policy that governs whether we federate an article via a feed +// +type FeedPolicy struct { + // list of whitelist regexps for newsgorups + Whitelist []string `json:"whitelist"` + // list of blacklist regexps for newsgroups + Blacklist []string `json:"blacklist"` + // are anon posts of any kind allowed? + AllowAnonPosts bool `json:"anon"` + // are anon posts with attachments allowed? + AllowAnonAttachments bool `json:"anon_attachments"` + // are any attachments allowed? + AllowAttachments bool `json:"attachments"` + // do we require Proof Of Work for untrusted connections? + UntrustedRequiresPoW bool `json:"pow"` +} + +// default feed policy to be used if not configured explicitly +var DefaultFeedPolicy = &FeedPolicy{ + Whitelist: []string{"ctl", "overchan.test"}, + Blacklist: []string{`!^overchan\.`}, + AllowAnonPosts: true, + AllowAnonAttachments: false, + UntrustedRequiresPoW: true, + AllowAttachments: true, +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/nntp/server.go b/contrib/backends/nntpchand/src/nntpchan/lib/nntp/server.go new file mode 100644 index 0000000..587e15d --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/nntp/server.go @@ -0,0 +1,326 @@ +package nntp + +import ( + log "github.com/Sirupsen/logrus" + "net" + "nntpchan/lib/config" + "nntpchan/lib/network" + "nntpchan/lib/store" + "time" +) + +// nntp outfeed state +type nntpFeed struct { + conn Conn + send chan ArticleEntry + conf *config.FeedConfig +} + +// an nntp server +type Server struct { + // user callback + Hooks EventHooks + // filters to apply + Filters []ArticleFilter + // global article acceptor + Acceptor ArticleAcceptor + // article storage + Storage store.Storage + // nntp config + Config *config.NNTPServerConfig + // outfeeds to connect to + Feeds []*config.FeedConfig + // inbound authentiaction mechanism + Auth ServerAuth + // send to outbound feed channel + send chan ArticleEntry + // register inbound feed channel + regis chan *nntpFeed + // deregister inbound feed channel + deregis chan *nntpFeed +} + +func NewServer() *Server { + return &Server{ + // XXX: buffered? + send: make(chan ArticleEntry), + regis: make(chan *nntpFeed), + deregis: make(chan *nntpFeed), + } +} + +// reload server configuration +func (s *Server) ReloadServer(c *config.NNTPServerConfig) { + +} + +// reload feeds +func (s *Server) ReloadFeeds(feeds []*config.FeedConfig) { + +} + +func (s *Server) GotArticle(msgid MessageID, group Newsgroup) { + log.WithFields(log.Fields{ + "pkg": "nntp-server", + "msgid": msgid, + "group": group, + }).Info("obtained article") + if s.Hooks != nil { + s.Hooks.GotArticle(msgid, group) + } + // send to outbound feeds + s.send <- ArticleEntry{msgid.String(), group.String()} +} + +func (s *Server) SentArticleVia(msgid MessageID, feedname string) { + log.WithFields(log.Fields{ + "pkg": "nntp-server", + "msgid": msgid, + "feed": feedname, + }).Info("article sent") + if s.Hooks != nil { + s.Hooks.SentArticleVia(msgid, feedname) + } +} + +func (s *Server) Name() string { + if s.Config == nil || s.Config.Name == "" { + return "nntp.anon.tld" + } + return s.Config.Name +} + +// persist 1 feed forever +func (s *Server) persist(cfg *config.FeedConfig) { + delay := time.Second + + log.WithFields(log.Fields{ + "name": cfg.Name, + }).Debug("Persist Feed") + for { + dialer := network.NewDialer(cfg.Proxy) + c, err := dialer.Dial(cfg.Addr) + if err == nil { + // successful connect + delay = time.Second + conn := newOutboundConn(c, s, cfg) + err = conn.Negotiate(true) + if err == nil { + // negotiation good + log.WithFields(log.Fields{ + "name": cfg.Name, + }).Debug("Negotitation good") + // start streaming + var chnl chan ArticleEntry + chnl, err = conn.StartStreaming() + if err == nil { + // register new connection + f := &nntpFeed{ + conn: conn, + send: chnl, + conf: cfg, + } + s.regis <- f + // start streaming + conn.StreamAndQuit() + // deregister + s.deregis <- f + continue + } + } else { + log.WithFields(log.Fields{ + "name": cfg.Name, + }).Info("outbound nntp connection failed to negotiate ", err) + } + conn.Quit() + } else { + // failed dial, do exponential backoff up to 1 hour + if delay <= time.Hour { + delay *= 2 + } + log.WithFields(log.Fields{ + "name": cfg.Name, + }).Info("feed backoff for ", delay) + time.Sleep(delay) + } + } +} + +// download all new posts from a remote server +func (s *Server) downloadPosts(cfg *config.FeedConfig) error { + dialer := network.NewDialer(cfg.Proxy) + c, err := dialer.Dial(cfg.Addr) + if err != nil { + return err + } + conn := newOutboundConn(c, s, cfg) + err = conn.Negotiate(false) + if err != nil { + conn.Quit() + return err + } + groups, err := conn.ListNewsgroups() + if err != nil { + conn.Quit() + return err + } + for _, g := range groups { + if cfg.Policy != nil && cfg.Policy.AllowGroup(g.String()) { + log.WithFields(log.Fields{ + "group": g, + "pkg": "nntp-server", + }).Debug("downloading group") + err = conn.DownloadGroup(g) + if err != nil { + conn.Quit() + return err + } + } + } + conn.Quit() + return nil +} + +func (s *Server) periodicDownload(cfg *config.FeedConfig) { + for cfg.PullInterval > 0 { + err := s.downloadPosts(cfg) + if err != nil { + // report error + log.WithFields(log.Fields{ + "feed": cfg.Name, + "pkg": "nntp-server", + "error": err, + }).Error("periodic download failed") + } + time.Sleep(time.Minute * time.Duration(cfg.PullInterval)) + } +} + +// persist all outbound feeds +func (s *Server) PersistFeeds() { + for _, f := range s.Feeds { + go s.persist(f) + go s.periodicDownload(f) + } + + feeds := make(map[string]*nntpFeed) + + for { + select { + case e, ok := <-s.send: + if !ok { + break + } + msgid := e.MessageID().String() + group := e.Newsgroup().String() + // TODO: determine anon + anon := false + // TODO: determine attachments + attachments := false + + for _, f := range feeds { + if f.conf.Policy != nil && !f.conf.Policy.Allow(msgid, group, anon, attachments) { + // not allowed in this feed + continue + } + log.WithFields(log.Fields{ + "name": f.conf.Name, + "msgid": msgid, + "group": group, + }).Debug("sending article") + f.send <- e + } + break + case f, ok := <-s.regis: + if ok { + log.WithFields(log.Fields{ + "name": f.conf.Name, + }).Debug("register feed") + feeds[f.conf.Name] = f + } + break + case f, ok := <-s.deregis: + if ok { + log.WithFields(log.Fields{ + "name": f.conf.Name, + }).Debug("deregister feed") + delete(feeds, f.conf.Name) + } + break + } + } +} + +// serve connections from listener +func (s *Server) Serve(l net.Listener) (err error) { + log.WithFields(log.Fields{ + "pkg": "nntp-server", + "addr": l.Addr(), + }).Debug("Serving") + for err == nil { + var c net.Conn + c, err = l.Accept() + if err == nil { + // we got a new connection + go s.handleInboundConnection(c) + } else { + log.WithFields(log.Fields{ + "pkg": "nntp-server", + }).Error("failed to accept inbound connection", err) + } + } + return +} + +// get the article policy for a connection given its state +func (s *Server) getPolicyFor(state *ConnState) ArticleAcceptor { + return s.Acceptor +} + +// recv inbound streaming messages +func (s *Server) recvInboundStream(chnl chan ArticleEntry) { + for { + e, ok := <-chnl + if ok { + s.GotArticle(e.MessageID(), e.Newsgroup()) + } else { + return + } + } +} + +// process an inbound connection +func (s *Server) handleInboundConnection(c net.Conn) { + log.WithFields(log.Fields{ + "pkg": "nntp-server", + "addr": c.RemoteAddr(), + }).Debug("handling inbound connection") + var nc Conn + nc = newInboundConn(s, c) + err := nc.Negotiate(true) + if err == nil { + // do they want to stream? + if nc.WantsStreaming() { + // yeeeeeh let's stream + var chnl chan ArticleEntry + chnl, err = nc.StartStreaming() + // for inbound we will recv messages + go s.recvInboundStream(chnl) + nc.StreamAndQuit() + log.WithFields(log.Fields{ + "pkg": "nntp-server", + "addr": c.RemoteAddr(), + }).Info("streaming finished") + return + } else { + // handle non streaming commands + nc.ProcessInbound(s) + } + } else { + log.WithFields(log.Fields{ + "pkg": "nntp-server", + "addr": c.RemoteAddr(), + }).Warn("failed to negotiate with inbound connection", err) + c.Close() + } +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/nntp/state.go b/contrib/backends/nntpchand/src/nntpchan/lib/nntp/state.go new file mode 100644 index 0000000..babb030 --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/nntp/state.go @@ -0,0 +1,21 @@ +package nntp + +// state of an nntp connection +type ConnState struct { + // name of parent feed + FeedName string `json:"feedname"` + // name of the connection + ConnName string `json:"connname"` + // hostname of remote connection + HostName string `json:"hostname"` + // current nntp mode + Mode Mode `json:"mode"` + // current selected nntp newsgroup + Group Newsgroup `json:"newsgroup"` + // current selected nntp article + Article string `json:"article"` + // parent feed's policy + Policy *FeedPolicy `json:"feedpolicy"` + // is this connection open? + Open bool `json:"open"` +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/nntp/streaming.go b/contrib/backends/nntpchand/src/nntpchan/lib/nntp/streaming.go new file mode 100644 index 0000000..8d267ef --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/nntp/streaming.go @@ -0,0 +1,65 @@ +package nntp + +import ( + "fmt" + "strings" +) + +// an nntp stream event +// these are pipelined between nntp servers +type StreamEvent string + +func (ev StreamEvent) MessageID() MessageID { + parts := strings.Split(string(ev), " ") + if len(parts) > 1 { + return MessageID(parts[1]) + } + return "" +} + +func (ev StreamEvent) String() string { + return string(ev) +} + +func (ev StreamEvent) Command() string { + return strings.Split(ev.String(), " ")[0] +} + +func (ev StreamEvent) Valid() bool { + return strings.Count(ev.String(), " ") == 1 && ev.MessageID().Valid() +} + +var stream_TAKETHIS = "TAKETHIS" +var stream_CHECK = "CHECK" + +func createStreamEvent(cmd string, msgid MessageID) StreamEvent { + if msgid.Valid() { + return StreamEvent(fmt.Sprintf("%s %s", cmd, msgid)) + } else { + return "" + } +} + +func stream_rpl_Accept(msgid MessageID) StreamEvent { + return createStreamEvent(RPL_StreamingAccept, msgid) +} + +func stream_rpl_Reject(msgid MessageID) StreamEvent { + return createStreamEvent(RPL_StreamingReject, msgid) +} + +func stream_rpl_Defer(msgid MessageID) StreamEvent { + return createStreamEvent(RPL_StreamingDefer, msgid) +} + +func stream_rpl_Failed(msgid MessageID) StreamEvent { + return createStreamEvent(RPL_StreamingFailed, msgid) +} + +func stream_cmd_TAKETHIS(msgid MessageID) StreamEvent { + return createStreamEvent(stream_TAKETHIS, msgid) +} + +func stream_cmd_CHECK(msgid MessageID) StreamEvent { + return createStreamEvent(stream_CHECK, msgid) +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/srnd/doc.go b/contrib/backends/nntpchand/src/nntpchan/lib/srnd/doc.go new file mode 100644 index 0000000..bbfbf9e --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/srnd/doc.go @@ -0,0 +1,5 @@ +// +// main package for srndv2 +// called from main +// +package srnd diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/store/doc.go b/contrib/backends/nntpchand/src/nntpchan/lib/store/doc.go new file mode 100644 index 0000000..fcce618 --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/store/doc.go @@ -0,0 +1,4 @@ +// +// nntp article storage +// +package store diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/store/fs.go b/contrib/backends/nntpchand/src/nntpchan/lib/store/fs.go new file mode 100644 index 0000000..83f5e51 --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/store/fs.go @@ -0,0 +1,416 @@ +package store + +import ( + "encoding/base32" + "fmt" + log "github.com/Sirupsen/logrus" + "io" + "io/ioutil" + "net/textproto" + "nntpchan/lib/crypto" + "os" + "path/filepath" + "strconv" + "time" +) + +const HighWaterHeader = "X-High-Water" +const LowWaterHeader = "X-Low-Water" + +// filesystem storage of nntp articles and attachments +type FilesystemStorage struct { + root string + discardAttachments bool +} + +func (fs FilesystemStorage) String() string { + return fs.root +} + +func (fs FilesystemStorage) NewsgroupsDir() string { + return filepath.Join(fs.root, "newsgroups") +} + +func (fs FilesystemStorage) metadataFileForNewsgroup(newsgroup string) string { + return filepath.Join(fs.newsgroupDir(newsgroup), "metadata") +} + +func (fs FilesystemStorage) GetWatermark(newsgroup string) (hi, lo uint64, err error) { + var hdr textproto.MIMEHeader + hdr, err = fs.getMetadataForNewsgroup(newsgroup) + if err == nil { + hi, err = strconv.ParseUint(hdr.Get(HighWaterHeader), 10, 64) + if err == nil { + lo, err = strconv.ParseUint(hdr.Get(LowWaterHeader), 10, 64) + } + } + return +} + +func (fs FilesystemStorage) getMetadataForNewsgroup(newsgroup string) (hdr textproto.MIMEHeader, err error) { + var f *os.File + fp := fs.metadataFileForNewsgroup(newsgroup) + _, err = os.Stat(fp) + if os.IsNotExist(err) { + f, err = os.OpenFile(fp, os.O_RDWR|os.O_CREATE, 0600) + if err == nil { + h := make(textproto.MIMEHeader) + h.Set(HighWaterHeader, "0") + c := textproto.NewConn(f) + for k := range hdr { + for _, v := range h[k] { + err = c.PrintfLine("%s: %s", k, v) + if err != nil { + c.Close() + return + } + } + } + c.Close() + } + } + f, err = os.OpenFile(fp, os.O_RDWR, 0600) + if err == nil { + c := textproto.NewConn(f) + hdr, err = c.ReadMIMEHeader() + c.Close() + } + return +} + +func (fs FilesystemStorage) nextIDForNewsgroup(newsgroup string) (id uint64, err error) { + id, _, err = fs.GetWatermark(newsgroup) + + if err == nil { + id++ + var hdr textproto.MIMEHeader + hdr, err = fs.getMetadataForNewsgroup(newsgroup) + if err == nil { + hdr.Set(HighWaterHeader, fmt.Sprintf("%d", id)) + var f *os.File + f, err = os.OpenFile(fs.metadataFileForNewsgroup(newsgroup), os.O_WRONLY, 0600) + if err == nil { + c := textproto.NewConn(f) + for k := range hdr { + for _, v := range hdr[k] { + err = c.PrintfLine("%s: %s", k, v) + if err != nil { + c.Close() + return + } + } + } + c.Close() + } + } + } + return +} + +func (fs FilesystemStorage) GetAllNewsgroups() (newsgroups []string, err error) { + err = filepath.Walk(fs.NewsgroupsDir(), filepath.WalkFunc(func(f string, info os.FileInfo, e error) (er error) { + if e != nil { + er = e + newsgroups = nil + } + if info.IsDir() && err == nil { + newsgroups = append(newsgroups, f) + } + return er + })) + return +} + +func (fs FilesystemStorage) HasNewsgroup(newsgroup string) (has bool, err error) { + _, err = os.Stat(fs.newsgroupDir(newsgroup)) + has = err == nil + return +} + +// ensure the filesystem storage exists and is well formed and read/writable +func (fs FilesystemStorage) Ensure() (err error) { + _, err = os.Stat(fs.String()) + if os.IsNotExist(err) { + // directory does not exist, create it + err = os.Mkdir(fs.String(), 0755) + if err != nil { + log.WithFields(log.Fields{ + "pkg": "fs-store", + "filepath": fs.String(), + }).Error("failed to ensure directory", err) + // failed to create initial directory + return + } + } + + // ensure subdirectories + for _, subdir := range []string{"att", "thm", "articles", "tmp", "newsgroups"} { + fpath := filepath.Join(fs.String(), subdir) + _, err = os.Stat(fpath) + if os.IsNotExist(err) { + // make subdirectory + err = os.Mkdir(fpath, 0755) + if err != nil { + log.WithFields(log.Fields{ + "pkg": "fs-store", + "filepath": fpath, + }).Error("failed to ensure sub-directory", err) + // failed to create subdirectory + return + } + } + } + return +} + +// get the temp file directory +func (fs FilesystemStorage) TempDir() string { + return filepath.Join(fs.String(), "tmp") +} + +// get the directory path for attachments +func (fs FilesystemStorage) AttachmentDir() string { + return filepath.Join(fs.String(), "att") +} + +// get the directory path for articles +func (fs FilesystemStorage) ArticleDir() string { + return filepath.Join(fs.String(), "articles") +} + +// get a temporary file we can use for read/write that deletes itself on close +func (fs FilesystemStorage) obtainTempFile() (f *os.File, err error) { + fname := fmt.Sprintf("tempfile-%x-%d", crypto.RandBytes(4), time.Now().Unix()) + log.WithFields(log.Fields{ + "pkg": "fs-store", + "filepath": fname, + }).Debug("opening temp file") + f, err = os.OpenFile(filepath.Join(fs.TempDir(), fname), os.O_RDWR|os.O_CREATE, 0400) + return +} + +// store an article from a reader to disk +func (fs FilesystemStorage) StoreArticle(r io.Reader, msgid, newsgroup string) (fpath string, err error) { + err = fs.HasArticle(msgid) + if err == nil { + // discard the body as we have it stored already + _, err = io.Copy(ioutil.Discard, r) + log.WithFields(log.Fields{ + "pkg": "fs-store", + "msgid": msgid, + }).Debug("discard article") + } else if err == ErrNoSuchArticle { + log.WithFields(log.Fields{ + "pkg": "fs-store", + "msgid": msgid, + }).Debug("storing article") + // don't have an article with this message id, write it to disk + var f *os.File + fpath = filepath.Join(fs.ArticleDir(), msgid) + f, err = os.OpenFile(fpath, os.O_CREATE|os.O_WRONLY, 0644) + if err == nil { + // file opened okay, defer the close + defer f.Close() + // write to disk + log.WithFields(log.Fields{ + "pkg": "fs-store", + "msgid": msgid, + }).Debug("writing to disk") + var n int64 + n, err = io.Copy(f, r) + if err == nil { + log.WithFields(log.Fields{ + "pkg": "fs-store", + "msgid": msgid, + "written": n, + }).Debug("wrote article to disk") + // symlink + g := fs.newsgroupDir(newsgroup) + _, e := os.Stat(g) + if os.IsNotExist(e) { + err = os.Mkdir(g, 0700) + } + var nntpid uint64 + nntpid, err = fs.nextIDForNewsgroup(newsgroup) + if err == nil { + err = os.Symlink(filepath.Join("..", "..", "articles", msgid), filepath.Join(g, fmt.Sprintf("%d", nntpid))) + } + if err != nil { + log.WithFields(log.Fields{ + "pkg": "fs-store", + "msgid": msgid, + "group": newsgroup, + }).Debug("failed to link article") + } + } else { + log.WithFields(log.Fields{ + "pkg": "fs-store", + "msgid": msgid, + "written": n, + }).Error("write to disk failed") + } + } else { + log.WithFields(log.Fields{ + "pkg": "fs-store", + "msgid": msgid, + "filepath": fpath, + }).Error("did not open file for storage", err) + } + } + return +} + +func (fs FilesystemStorage) newsgroupDir(group string) string { + return filepath.Join(fs.NewsgroupsDir(), group) +} + +// check if we have the artilce with this message id +func (fs FilesystemStorage) HasArticle(msgid string) (err error) { + fpath := fs.ArticleDir() + fpath = filepath.Join(fpath, msgid) + log.WithFields(log.Fields{ + "pkg": "fs-store", + "msgid": msgid, + "filepath": fpath, + }).Debug("check for article") + _, err = os.Stat(fpath) + if os.IsNotExist(err) { + err = ErrNoSuchArticle + } + return +} + +func (fs FilesystemStorage) DeleteArticle(msgid string) (err error) { + err = os.Remove(filepath.Join(fs.ArticleDir(), msgid)) + return +} + +// store attachment onto filesystem +func (fs FilesystemStorage) StoreAttachment(r io.Reader, filename string) (fpath string, err error) { + if fs.discardAttachments { + _, err = io.Copy(ioutil.Discard, r) + return + } + // open temp file for storage + var tf *os.File + tf, err = fs.obtainTempFile() + if err == nil { + // we have the temp file + + // close tempfile when done + defer func() { + n := tf.Name() + tf.Close() + os.Remove(n) + }() + + // create hasher + h := crypto.Hash() + // create multiwriter + mw := io.MultiWriter(tf, h) + + log.WithFields(log.Fields{ + "pkg": "fs-store", + "filename": filename, + }).Debug("writing to disk") + var n int64 + // write all of the reader to the multiwriter + n, err = io.Copy(mw, r) + + if err == nil { + // successful write + + // get file checksum + d := h.Sum(nil) + + // rename file to hash + extension from filename + fpath = base32.StdEncoding.EncodeToString(d) + filepath.Ext(filename) + fpath = filepath.Join(fs.AttachmentDir(), fpath) + + _, err = os.Stat(fpath) + // is that file there? + if os.IsNotExist(err) { + // it's not there, let's write it + var f *os.File + f, err = os.OpenFile(fpath, os.O_WRONLY|os.O_CREATE, 0644) + if err == nil { + // file opened + defer f.Close() + // seek to beginning of tempfile + tf.Seek(0, os.SEEK_SET) + // write all of the temp file to the storage file + n, err = io.Copy(f, tf) + // if err == nil by here it's all good + l := log.WithFields(log.Fields{ + "pkg": "fs-store", + "filename": filename, + "hash": d, + "filepath": fpath, + "size": n, + }) + if err == nil { + l.Debug("wrote attachment to disk") + } else { + l.Error("failed to write attachment to disk", err) + } + } else { + log.WithFields(log.Fields{ + "pkg": "fs-store", + "filename": filename, + "hash": d, + "filepath": fpath, + }).Error("failed to open file") + } + } else { + log.WithFields(log.Fields{ + "pkg": "fs-store", + "filename": filename, + "hash": d, + "filepath": fpath, + "size": n, + }).Debug("attachment exists on disk") + } + } + } else { + log.WithFields(log.Fields{ + "pkg": "fs-store", + "filename": filename, + }).Error("cannot open temp file for attachment", err) + } + return +} + +// open article given message-id +// does not check validity +func (fs FilesystemStorage) OpenArticle(msgid string) (r *os.File, err error) { + r, err = os.Open(filepath.Join(fs.ArticleDir(), msgid)) + return +} + +func (fs FilesystemStorage) ForEachInGroup(group string, chnl chan string) { + g := fs.newsgroupDir(group) + filepath.Walk(g, func(path string, info os.FileInfo, err error) error { + if info != nil { + chnl <- info.Name() + } + return err + }) +} + +// create a new filesystem storage directory +// ensure directory and subdirectories +func NewFilesytemStorage(dirname string, unpackAttachments bool) (fs FilesystemStorage, err error) { + dirname, err = filepath.Abs(dirname) + if err == nil { + log.WithFields(log.Fields{ + "pkg": "fs-store", + "filepath": dirname, + }).Info("Creating New Filesystem Storage") + fs = FilesystemStorage{ + root: dirname, + discardAttachments: unpackAttachments, + } + err = fs.Ensure() + } + return +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/store/log.go b/contrib/backends/nntpchand/src/nntpchan/lib/store/log.go new file mode 100644 index 0000000..72440ea --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/store/log.go @@ -0,0 +1 @@ +package store diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/store/null.go b/contrib/backends/nntpchand/src/nntpchan/lib/store/null.go new file mode 100644 index 0000000..db0ff96 --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/store/null.go @@ -0,0 +1,62 @@ +package store + +import ( + "io" + "nntpchan/lib/util" + "os" +) + +type nullStore struct{} + +func (n *nullStore) discard(r io.Reader) (s string, err error) { + _, err = io.Copy(util.Discard, r) + s = "/dev/null" + return +} + +func (n *nullStore) HasArticle(msgid string) error { + return ErrNoSuchArticle +} + +func (n *nullStore) StoreAttachment(r io.Reader, filename string) (string, error) { + return n.discard(r) +} + +func (n *nullStore) StoreArticle(r io.Reader, msgid, newsgroup string) (string, error) { + return n.discard(r) +} + +func (n *nullStore) DeleteArticle(msgid string) (err error) { + return +} + +func (n *nullStore) Ensure() (err error) { + return +} + +func (n *nullStore) ForEachInGroup(newsgroup string, chnl chan string) { + return +} + +func (n *nullStore) OpenArticle(msgid string) (r *os.File, err error) { + err = ErrNoSuchArticle + return +} + +func (n *nullStore) HasNewsgroup(newsgroup string) (has bool, err error) { + has = true + return +} + +func (n *nullStore) GetAllNewsgroups() (list []string, err error) { + return +} + +func (n *nullStore) GetWatermark(newsgroup string) (hi, lo uint64, err error) { + return +} + +// create a storage backend that does nothing +func NewNullStorage() Storage { + return &nullStore{} +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/store/store.go b/contrib/backends/nntpchand/src/nntpchan/lib/store/store.go new file mode 100644 index 0000000..aeef6bd --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/store/store.go @@ -0,0 +1,50 @@ +package store + +import ( + "errors" + "io" + "os" +) + +var ErrNoSuchArticle = errors.New("no such article") + +// storage for nntp articles and attachments +type Storage interface { + // store an attachment that we read from an io.Reader + // filename is used to hint to store what extension to store it as + // returns absolute filepath where attachment was stored and nil on success + // returns emtpy string and error if an error ocurred while storing + StoreAttachment(r io.Reader, filename string) (string, error) + + // store an article that we read from an io.Reader + // message id is used to hint where the article is stored as well as newsgroup + // returns absolute filepath to where the article was stored and nil on success + // returns empty string and error if an error ocurred while storing + StoreArticle(r io.Reader, msgid, newsgroup string) (string, error) + + // return nil if the article with the given message id exists in this storage + // return ErrNoSuchArticle if it does not exist or an error if another error occured while checking + HasArticle(msgid string) error + + // delete article from underlying storage + DeleteArticle(msgid string) error + + // open article for reading + OpenArticle(msgid string) (*os.File, error) + + // ensure the underlying storage backend is created + Ensure() error + + // iterate over all messages in a newsgroup + // send results down a channel + ForEachInGroup(newsgroup string, cnhl chan string) + + // get a list of all newsgroups + GetAllNewsgroups() ([]string, error) + + // determine if we have a newsgroup + HasNewsgroup(newsgroup string) (bool, error) + + // get hi/lo watermark for newsgroup + GetWatermark(newsgroup string) (uint64, uint64, error) +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/thumbnail/doc.go b/contrib/backends/nntpchand/src/nntpchan/lib/thumbnail/doc.go new file mode 100644 index 0000000..dc9aaa1 --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/thumbnail/doc.go @@ -0,0 +1,4 @@ +// +// attachment thumbnailing +// +package thumbnail diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/thumbnail/exec.go b/contrib/backends/nntpchand/src/nntpchan/lib/thumbnail/exec.go new file mode 100644 index 0000000..5b0ef9d --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/thumbnail/exec.go @@ -0,0 +1,40 @@ +package thumbnail + +import ( + "os/exec" + "regexp" +) + +// thumbnail by executing an external program +type ExecThumbnailer struct { + // path to executable + Exec string + // regular expression that checks for acceptable infiles + Accept *regexp.Regexp + // function to generate arguments to use with external program + // inf and outf are the filenames of the input and output files respectively + // if this is nil the command will be passed in 2 arguments, infile and outfile + GenArgs func(inf, outf string) []string +} + +func (exe *ExecThumbnailer) CanThumbnail(infpath string) bool { + re := exe.Accept.Copy() + return re.MatchString(infpath) +} + +func (exe *ExecThumbnailer) Generate(infpath, outfpath string) (err error) { + // do sanity check + if exe.CanThumbnail(infpath) { + var args []string + if exe.GenArgs == nil { + args = []string{infpath, outfpath} + } else { + args = exe.GenArgs(infpath, outfpath) + } + cmd := exec.Command(exe.Exec, args...) + _, err = cmd.CombinedOutput() + } else { + err = ErrCannotThumbanil + } + return +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/thumbnail/multi.go b/contrib/backends/nntpchand/src/nntpchan/lib/thumbnail/multi.go new file mode 100644 index 0000000..1a26e58 --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/thumbnail/multi.go @@ -0,0 +1,47 @@ +package thumbnail + +import ( + "errors" +) + +var ErrNoThumbnailer = errors.New("no thumbnailer found") + +type multiThumbnailer struct { + impls []Thumbnailer +} + +// get the frist matching thumbnailer that works with the given file +// if we can't find one return nil +func (mth *multiThumbnailer) getThumbnailer(fpath string) Thumbnailer { + for _, th := range mth.impls { + if th.CanThumbnail(fpath) { + return th + } + } + return nil +} + +func (mth *multiThumbnailer) Generate(infpath, outfpath string) (err error) { + th := mth.getThumbnailer(infpath) + if th == nil { + err = ErrNoThumbnailer + } else { + err = th.Generate(infpath, outfpath) + } + return +} + +func (mth *multiThumbnailer) CanThumbnail(infpath string) bool { + for _, th := range mth.impls { + if th.CanThumbnail(infpath) { + return true + } + } + return false +} + +func MuxThumbnailers(th ...Thumbnailer) Thumbnailer { + return &multiThumbnailer{ + impls: th, + } +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/thumbnail/thumb.go b/contrib/backends/nntpchand/src/nntpchan/lib/thumbnail/thumb.go new file mode 100644 index 0000000..a974053 --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/thumbnail/thumb.go @@ -0,0 +1,76 @@ +package thumbnail + +import ( + "errors" + "fmt" + "regexp" + "strings" +) + +var ErrCannotThumbanil = errors.New("cannot thumbnail file") + +// a generator of thumbnails +type Thumbnailer interface { + // generate thumbnail of attachment + // + // infpath: absolute filepath to attachment + // + // outfpath: absolute filepath to thumbnail + // + // return error if the thumbnailing fails + Generate(infpath, outfpath string) error + + // can we generate a thumbnail for this file? + CanThumbnail(infpath string) bool +} + +// thumbnail configuration +type Config struct { + // width of thumbnails + ThumbW int + // height of thumbnails + ThumbH int + // only generate jpg thumbnails + JpegOnly bool +} + +var defaultCfg = &Config{ + ThumbW: 300, + ThumbH: 200, + JpegOnly: true, +} + +// create an imagemagick thumbnailer +func ImageMagickThumbnailer(convertPath string, conf *Config) Thumbnailer { + if conf == nil { + conf = defaultCfg + } + return &ExecThumbnailer{ + Exec: convertPath, + Accept: regexp.MustCompilePOSIX(`\.(png|jpg|jpeg|gif|webp)$`), + GenArgs: func(inf, outf string) []string { + if strings.HasSuffix(inf, ".gif") { + inf += "[0]" + } + if conf.JpegOnly { + outf += ".jpeg" + } + return []string{"-thumbnail", fmt.Sprintf("%d", conf.ThumbW), inf, outf} + }, + } +} + +// generate a thumbnailer that uses ffmpeg +func FFMpegThumbnailer(ffmpegPath string, conf *Config) Thumbnailer { + if conf == nil { + conf = defaultCfg + } + return &ExecThumbnailer{ + Exec: ffmpegPath, + Accept: regexp.MustCompilePOSIX(`\.(mkv|mp4|avi|webm|ogv|mov|m4v|mpg)$`), + GenArgs: func(inf, outf string) []string { + outf += ".jpeg" + return []string{"-i", inf, "-vf", fmt.Sprintf("scale=%d:%d", conf.ThumbW, conf.ThumbH), "-vframes", "1", outf} + }, + } +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/thumbnail/thumb_test.go b/contrib/backends/nntpchand/src/nntpchan/lib/thumbnail/thumb_test.go new file mode 100644 index 0000000..3796155 --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/thumbnail/thumb_test.go @@ -0,0 +1,56 @@ +package thumbnail + +import ( + "testing" +) + +func doTestThumb(t *testing.T, th Thumbnailer, allowed, disallowed []string) { + for _, f := range allowed { + if !th.CanThumbnail(f) { + t.Logf("cannot thumbnail expected file: %s", f) + t.Fail() + } + } + + for _, f := range disallowed { + if th.CanThumbnail(f) { + t.Logf("can thumbnail wrong file: %s", f) + t.Fail() + } + } + +} + +var _image = []string{"asd.gif", "asd.jpeg", "asd.jpg", "asd.png", "asd.webp"} +var _video = []string{"asd.mkv", "asd.mov", "asd.mp4", "asd.m4v", "asd.ogv", "asd.avi", "asd.mpg", "asd.webm"} +var _sound = []string{"asd.flac", "asd.mp3", "asd.mp2", "asd.wav", "asd.ogg", "asd.opus", "asd.m4a"} +var _misc = []string{"asd.txt", "asd.swf"} +var _garbage = []string{"asd", "asd.asd", "asd.asd.asd.asd", "asd.benis"} + +func TestCanThumbnailImage(t *testing.T) { + th := ImageMagickThumbnailer("", nil) + var allowed []string + var disallowed []string + + allowed = append(allowed, _image...) + disallowed = append(disallowed, _video...) + disallowed = append(disallowed, _sound...) + disallowed = append(disallowed, _misc...) + disallowed = append(disallowed, _garbage...) + + doTestThumb(t, th, allowed, disallowed) +} + +func TestCanThumbnailVideo(t *testing.T) { + th := FFMpegThumbnailer("", nil) + var allowed []string + var disallowed []string + + allowed = append(allowed, _video...) + disallowed = append(disallowed, _image...) + disallowed = append(disallowed, _sound...) + disallowed = append(disallowed, _misc...) + disallowed = append(disallowed, _garbage...) + + doTestThumb(t, th, allowed, disallowed) +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/util/cache.go b/contrib/backends/nntpchand/src/nntpchan/lib/util/cache.go new file mode 100644 index 0000000..0f1b3e4 --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/util/cache.go @@ -0,0 +1,87 @@ +package util + +import ( + "fmt" + "path/filepath" + "regexp" + "strconv" +) + +func GetThreadHashHTML(file string) (thread string) { + exp := regexp.MustCompilePOSIX(`thread-([0-9a-f]+)\.html`) + matches := exp.FindStringSubmatch(file) + if len(matches) != 2 { + return "" + } + thread = matches[1] + return +} + +func GetGroupAndPageHTML(file string) (board string, page int) { + exp := regexp.MustCompilePOSIX(`(.*)-([0-9]+)\.html`) + matches := exp.FindStringSubmatch(file) + if len(matches) != 3 { + return "", -1 + } + var err error + board = matches[1] + tmp := matches[2] + page, err = strconv.Atoi(tmp) + if err != nil { + page = -1 + } + return +} + +func GetGroupForCatalogHTML(file string) (group string) { + exp := regexp.MustCompilePOSIX(`catalog-(.+)\.html`) + matches := exp.FindStringSubmatch(file) + if len(matches) != 2 { + return "" + } + group = matches[1] + return +} + +func GetFilenameForBoardPage(webroot_dir, boardname string, pageno int, json bool) string { + var ext string + if json { + ext = "json" + } else { + ext = "html" + } + fname := fmt.Sprintf("%s-%d.%s", boardname, pageno, ext) + return filepath.Join(webroot_dir, fname) +} + +func GetFilenameForThread(webroot_dir, root_post_id string, json bool) string { + var ext string + if json { + ext = "json" + } else { + ext = "html" + } + fname := fmt.Sprintf("thread-%s.%s", HashMessageID(root_post_id), ext) + return filepath.Join(webroot_dir, fname) +} + +func GetFilenameForCatalog(webroot_dir, boardname string) string { + fname := fmt.Sprintf("catalog-%s.html", boardname) + return filepath.Join(webroot_dir, fname) +} + +func GetFilenameForIndex(webroot_dir string) string { + return filepath.Join(webroot_dir, "index.html") +} + +func GetFilenameForBoards(webroot_dir string) string { + return filepath.Join(webroot_dir, "boards.html") +} + +func GetFilenameForHistory(webroot_dir string) string { + return filepath.Join(webroot_dir, "history.html") +} + +func GetFilenameForUkko(webroot_dir string) string { + return filepath.Join(webroot_dir, "ukko.html") +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/util/discard.go b/contrib/backends/nntpchand/src/nntpchan/lib/util/discard.go new file mode 100644 index 0000000..4b954ff --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/util/discard.go @@ -0,0 +1,14 @@ +package util + +type ioDiscard struct{} + +func (discard *ioDiscard) Write(d []byte) (n int, err error) { + n = len(d) + return +} + +func (discard *ioDiscard) Close() (err error) { + return +} + +var Discard = new(ioDiscard) diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/util/hex.go b/contrib/backends/nntpchand/src/nntpchan/lib/util/hex.go new file mode 100644 index 0000000..5d4e588 --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/util/hex.go @@ -0,0 +1,11 @@ +package util + +import ( + "crypto/sha1" + "fmt" +) + +// message id hash +func HashMessageID(msgid string) string { + return fmt.Sprintf("%x", sha1.Sum([]byte(msgid))) +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/util/ip.go b/contrib/backends/nntpchand/src/nntpchan/lib/util/ip.go new file mode 100644 index 0000000..da7333d --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/util/ip.go @@ -0,0 +1,91 @@ +package util + +import ( + "encoding/base64" + "fmt" + "log" + "net" + "nntpchan/lib/crypto/nacl" +) + +// given an address +// generate a new encryption key for it +// return the encryption key and the encrypted address +func NewAddrEnc(addr string) (string, string) { + key_bytes := nacl.RandBytes(encAddrBytes()) + key := base64.StdEncoding.EncodeToString(key_bytes) + return key, EncAddr(addr, key) +} + +// xor address with a one time pad +// if the address isn't long enough it's padded with spaces +func EncAddr(addr, key string) string { + key_bytes, err := base64.StdEncoding.DecodeString(key) + + if err != nil { + log.Println("encAddr() key base64 decode", err) + return "" + } + + if len(addr) > len(key_bytes) { + log.Println("encAddr() len(addr) > len(key_bytes)") + return "" + } + + // pad with spaces + for len(addr) < len(key_bytes) { + addr += " " + } + + addr_bytes := []byte(addr) + res_bytes := make([]byte, len(addr_bytes)) + for idx, b := range key_bytes { + res_bytes[idx] = addr_bytes[idx] ^ b + } + + return base64.StdEncoding.EncodeToString(res_bytes) +} + +// number of bytes to use in otp +func encAddrBytes() int { + return 64 +} + +func IsSubnet(cidr string) (bool, *net.IPNet) { + _, ipnet, err := net.ParseCIDR(cidr) + if err == nil { + return true, ipnet + } + return false, nil +} + +func IPNet2MinMax(inet *net.IPNet) (min, max net.IP) { + netb := []byte(inet.IP) + maskb := []byte(inet.Mask) + maxb := make([]byte, len(netb)) + + for i, _ := range maxb { + maxb[i] = netb[i] | (^maskb[i]) + } + min = net.IP(netb) + max = net.IP(maxb) + return +} + +func ZeroIPString(ip net.IP) string { + p := ip + + if len(ip) == 0 { + return "" + } + + if p4 := p.To4(); len(p4) == net.IPv4len { + return fmt.Sprintf("%03d.%03d.%03d.%03d", p4[0], p4[1], p4[2], p4[3]) + } + if len(p) == net.IPv6len { + //>IPv6 + //ishygddt + return fmt.Sprintf("[%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]", p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]) + } + return "?" +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/util/nntp_login.go b/contrib/backends/nntpchand/src/nntpchan/lib/util/nntp_login.go new file mode 100644 index 0000000..1176810 --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/util/nntp_login.go @@ -0,0 +1,29 @@ +package util + +import ( + "crypto/sha512" + "encoding/base64" + "encoding/hex" + "nntpchan/lib/crypto/nacl" +) + +// generate a login salt for nntp users +func GenLoginCredSalt() (salt string) { + salt = randStr(128) + return +} + +// do nntp login credential hash given password and salt +func NntpLoginCredHash(passwd, salt string) (str string) { + var b []byte + b = append(b, []byte(passwd)...) + b = append(b, []byte(salt)...) + h := sha512.Sum512(b) + str = base64.StdEncoding.EncodeToString(h[:]) + return +} + +// make a random string +func randStr(length int) string { + return hex.EncodeToString(nacl.RandBytes(length))[length:] +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/util/post.go b/contrib/backends/nntpchand/src/nntpchan/lib/util/post.go new file mode 100644 index 0000000..2decff1 --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/util/post.go @@ -0,0 +1,8 @@ +package util + +import "strings" + +func IsSage(str string) bool { + str = strings.ToLower(str) + return str == "sage" || strings.HasPrefix(str, "sage ") +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/util/time.go b/contrib/backends/nntpchand/src/nntpchan/lib/util/time.go new file mode 100644 index 0000000..75a7ee4 --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/util/time.go @@ -0,0 +1,8 @@ +package util + +import "time" + +// time for right now as int64 +func TimeNow() int64 { + return time.Now().UTC().Unix() +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/webhooks/doc.go b/contrib/backends/nntpchand/src/nntpchan/lib/webhooks/doc.go new file mode 100644 index 0000000..5124e0b --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/webhooks/doc.go @@ -0,0 +1,4 @@ +// +// nntpchan web hooks +// +package webhooks diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/webhooks/http.go b/contrib/backends/nntpchand/src/nntpchan/lib/webhooks/http.go new file mode 100644 index 0000000..de76285 --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/webhooks/http.go @@ -0,0 +1,154 @@ +package webhooks + +import ( + "encoding/json" + "fmt" + log "github.com/Sirupsen/logrus" + "io" + "mime" + "mime/multipart" + "net/http" + "net/textproto" + "net/url" + "nntpchan/lib/config" + "nntpchan/lib/nntp" + "nntpchan/lib/nntp/message" + "nntpchan/lib/store" + "regexp" + "strings" +) + +// web hook implementation +type httpWebhook struct { + conf *config.WebhookConfig + storage store.Storage + hdr *message.HeaderIO +} + +func (h *httpWebhook) SentArticleVia(msgid nntp.MessageID, name string) { + // web hooks don't care about feed state +} + +// we got a new article +func (h *httpWebhook) GotArticle(msgid nntp.MessageID, group nntp.Newsgroup) { + h.sendArticle(msgid, group) +} + +func (h *httpWebhook) sendArticle(msgid nntp.MessageID, group nntp.Newsgroup) { + f, err := h.storage.OpenArticle(msgid.String()) + if err == nil { + u, _ := url.Parse(h.conf.URL) + var r *http.Response + var ctype string + if h.conf.Dialect == "vichan" { + c := textproto.NewConn(f) + var hdr textproto.MIMEHeader + hdr, err = c.ReadMIMEHeader() + if err == nil { + var body io.Reader + ctype = hdr.Get("Content-Type") + if ctype == "" || strings.HasPrefix(ctype, "text/plain") { + ctype = "text/plain" + } + ctype = strings.Replace(strings.ToLower(ctype), "multipart/mixed", "multipart/form-data", 1) + q := u.Query() + for k, vs := range hdr { + for _, v := range vs { + q.Add(k, v) + } + } + q.Set("Content-Type", ctype) + u.RawQuery = q.Encode() + + if strings.HasPrefix(ctype, "multipart") { + pr, pw := io.Pipe() + log.Debug("using pipe") + go func(in io.Reader, out io.WriteCloser) { + _, params, _ := mime.ParseMediaType(ctype) + if params == nil { + // send as whatever lol + io.Copy(out, in) + } else { + boundary, _ := params["boundary"] + mpr := multipart.NewReader(in, boundary) + mpw := multipart.NewWriter(out) + mpw.SetBoundary(boundary) + for { + part, err := mpr.NextPart() + if err == io.EOF { + err = nil + break + } else if err == nil { + // get part header + h := part.Header + // rewrite header part for php + cd := h.Get("Content-Disposition") + r := regexp.MustCompile(`filename="(.*)"`) + // YOLO + parts := r.FindStringSubmatch(cd) + if len(parts) > 1 { + fname := parts[1] + h.Set("Content-Disposition", fmt.Sprintf(`filename="%s"; name="attachment[]"`, fname)) + } + // make write part + wp, err := mpw.CreatePart(h) + if err == nil { + // write part out + io.Copy(wp, part) + } else { + log.Errorf("error writng webhook part: %s", err.Error()) + } + } + part.Close() + } + mpw.Close() + } + out.Close() + }(c.R, pw) + body = pr + } else { + body = f + } + r, err = http.Post(u.String(), ctype, body) + } + } else { + var sz int64 + sz, err = f.Seek(0, 2) + if err != nil { + return + } + f.Seek(0, 0) + // regular webhook + ctype = "text/plain; charset=UTF-8" + cl := new(http.Client) + r, err = cl.Do(&http.Request{ + ContentLength: sz, + URL: u, + Method: "POST", + Body: f, + }) + } + if err == nil && r != nil { + dec := json.NewDecoder(r.Body) + result := make(map[string]interface{}) + err = dec.Decode(&result) + if err == nil || err == io.EOF { + msg, ok := result["error"] + if ok { + log.Warnf("hook gave error: %s", msg) + } else { + log.Debugf("hook response: %s", result) + } + } else { + log.Warnf("hook response does not look like json: %s", err) + } + r.Body.Close() + log.Infof("hook called for %s", msgid) + } + } else { + f.Close() + } + if err != nil { + log.Errorf("error calling web hook %s: %s", h.conf.Name, err.Error()) + } +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/webhooks/multi.go b/contrib/backends/nntpchand/src/nntpchan/lib/webhooks/multi.go new file mode 100644 index 0000000..1cf0ce3 --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/webhooks/multi.go @@ -0,0 +1,23 @@ +package webhooks + +import ( + "nntpchan/lib/nntp" +) + +// webhook multiplexer +type multiWebhook struct { + hooks []Webhook +} + +// got an article +func (m *multiWebhook) GotArticle(msgid nntp.MessageID, group nntp.Newsgroup) { + for _, h := range m.hooks { + h.GotArticle(msgid, group) + } +} + +func (m *multiWebhook) SentArticleVia(msgid nntp.MessageID, feedname string) { + for _, h := range m.hooks { + h.SentArticleVia(msgid, feedname) + } +} diff --git a/contrib/backends/nntpchand/src/nntpchan/lib/webhooks/webhooks.go b/contrib/backends/nntpchand/src/nntpchan/lib/webhooks/webhooks.go new file mode 100644 index 0000000..cd6826b --- /dev/null +++ b/contrib/backends/nntpchand/src/nntpchan/lib/webhooks/webhooks.go @@ -0,0 +1,30 @@ +package webhooks + +import ( + "nntpchan/lib/config" + "nntpchan/lib/nntp" + "nntpchan/lib/nntp/message" + "nntpchan/lib/store" +) + +type Webhook interface { + // implements nntp.EventHooks + nntp.EventHooks +} + +// create webhook multiplexing multiple web hooks +func NewWebhooks(conf []*config.WebhookConfig, st store.Storage) Webhook { + h := message.NewHeaderIO() + var hooks []Webhook + for _, c := range conf { + hooks = append(hooks, &httpWebhook{ + conf: c, + storage: st, + hdr: h, + }) + } + + return &multiWebhook{ + hooks: hooks, + } +} diff --git a/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/.gitignore b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/.gitignore new file mode 100644 index 0000000..66be63a --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/.gitignore @@ -0,0 +1 @@ +logrus diff --git a/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/.travis.yml b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/.travis.yml new file mode 100644 index 0000000..2d8c086 --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/.travis.yml @@ -0,0 +1,8 @@ +language: go +go: + - 1.2 + - 1.3 + - 1.4 + - tip +install: + - go get -t ./... diff --git a/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/CHANGELOG.md b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/CHANGELOG.md new file mode 100644 index 0000000..b1fe4b6 --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/CHANGELOG.md @@ -0,0 +1,41 @@ +# 0.8.6 + +* hooks/raven: allow passing an initialized client + +# 0.8.5 + +* logrus/core: revert #208 + +# 0.8.4 + +* formatter/text: fix data race (#218) + +# 0.8.3 + +* logrus/core: fix entry log level (#208) +* logrus/core: improve performance of text formatter by 40% +* logrus/core: expose `LevelHooks` type +* logrus/core: add support for DragonflyBSD and NetBSD +* formatter/text: print structs more verbosely + +# 0.8.2 + +* logrus: fix more Fatal family functions + +# 0.8.1 + +* logrus: fix not exiting on `Fatalf` and `Fatalln` + +# 0.8.0 + +* logrus: defaults to stderr instead of stdout +* hooks/sentry: add special field for `*http.Request` +* formatter/text: ignore Windows for colors + +# 0.7.3 + +* formatter/\*: allow configuration of timestamp layout + +# 0.7.2 + +* formatter/text: Add configuration option for time format (#158) diff --git a/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/LICENSE b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/LICENSE new file mode 100644 index 0000000..f090cb4 --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Simon Eskildsen + +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/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/README.md b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/README.md new file mode 100644 index 0000000..9f712a7 --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/README.md @@ -0,0 +1,357 @@ +# Logrus :walrus: [![Build Status](https://travis-ci.org/Sirupsen/logrus.svg?branch=master)](https://travis-ci.org/Sirupsen/logrus) [![godoc reference](https://godoc.org/github.com/Sirupsen/logrus?status.png)][godoc] + +Logrus is a structured logger for Go (golang), completely API compatible with +the standard library logger. [Godoc][godoc]. **Please note the Logrus API is not +yet stable (pre 1.0). Logrus itself is completely stable and has been used in +many large deployments. The core API is unlikely to change much but please +version control your Logrus to make sure you aren't fetching latest `master` on +every build.** + +Nicely color-coded in development (when a TTY is attached, otherwise just +plain text): + +![Colored](http://i.imgur.com/PY7qMwd.png) + +With `log.Formatter = new(logrus.JSONFormatter)`, for easy parsing by logstash +or Splunk: + +```json +{"animal":"walrus","level":"info","msg":"A group of walrus emerges from the +ocean","size":10,"time":"2014-03-10 19:57:38.562264131 -0400 EDT"} + +{"level":"warning","msg":"The group's number increased tremendously!", +"number":122,"omg":true,"time":"2014-03-10 19:57:38.562471297 -0400 EDT"} + +{"animal":"walrus","level":"info","msg":"A giant walrus appears!", +"size":10,"time":"2014-03-10 19:57:38.562500591 -0400 EDT"} + +{"animal":"walrus","level":"info","msg":"Tremendously sized cow enters the ocean.", +"size":9,"time":"2014-03-10 19:57:38.562527896 -0400 EDT"} + +{"level":"fatal","msg":"The ice breaks!","number":100,"omg":true, +"time":"2014-03-10 19:57:38.562543128 -0400 EDT"} +``` + +With the default `log.Formatter = new(&log.TextFormatter{})` when a TTY is not +attached, the output is compatible with the +[logfmt](http://godoc.org/github.com/kr/logfmt) format: + +```text +time="2015-03-26T01:27:38-04:00" level=debug msg="Started observing beach" animal=walrus number=8 +time="2015-03-26T01:27:38-04:00" level=info msg="A group of walrus emerges from the ocean" animal=walrus size=10 +time="2015-03-26T01:27:38-04:00" level=warning msg="The group's number increased tremendously!" number=122 omg=true +time="2015-03-26T01:27:38-04:00" level=debug msg="Temperature changes" temperature=-4 +time="2015-03-26T01:27:38-04:00" level=panic msg="It's over 9000!" animal=orca size=9009 +time="2015-03-26T01:27:38-04:00" level=fatal msg="The ice breaks!" err=&{0x2082280c0 map[animal:orca size:9009] 2015-03-26 01:27:38.441574009 -0400 EDT panic It's over 9000!} number=100 omg=true +exit status 1 +``` + +#### Example + +The simplest way to use Logrus is simply the package-level exported logger: + +```go +package main + +import ( + log "github.com/Sirupsen/logrus" +) + +func main() { + log.WithFields(log.Fields{ + "animal": "walrus", + }).Info("A walrus appears") +} +``` + +Note that it's completely api-compatible with the stdlib logger, so you can +replace your `log` imports everywhere with `log "github.com/Sirupsen/logrus"` +and you'll now have the flexibility of Logrus. You can customize it all you +want: + +```go +package main + +import ( + "os" + log "github.com/Sirupsen/logrus" + "github.com/Sirupsen/logrus/hooks/airbrake" +) + +func init() { + // Log as JSON instead of the default ASCII formatter. + log.SetFormatter(&log.JSONFormatter{}) + + // Use the Airbrake hook to report errors that have Error severity or above to + // an exception tracker. You can create custom hooks, see the Hooks section. + log.AddHook(airbrake.NewHook("https://example.com", "xyz", "development")) + + // Output to stderr instead of stdout, could also be a file. + log.SetOutput(os.Stderr) + + // Only log the warning severity or above. + log.SetLevel(log.WarnLevel) +} + +func main() { + log.WithFields(log.Fields{ + "animal": "walrus", + "size": 10, + }).Info("A group of walrus emerges from the ocean") + + log.WithFields(log.Fields{ + "omg": true, + "number": 122, + }).Warn("The group's number increased tremendously!") + + log.WithFields(log.Fields{ + "omg": true, + "number": 100, + }).Fatal("The ice breaks!") + + // A common pattern is to re-use fields between logging statements by re-using + // the logrus.Entry returned from WithFields() + contextLogger := log.WithFields(log.Fields{ + "common": "this is a common field", + "other": "I also should be logged always", + }) + + contextLogger.Info("I'll be logged with common and other field") + contextLogger.Info("Me too") +} +``` + +For more advanced usage such as logging to multiple locations from the same +application, you can also create an instance of the `logrus` Logger: + +```go +package main + +import ( + "github.com/Sirupsen/logrus" +) + +// Create a new instance of the logger. You can have any number of instances. +var log = logrus.New() + +func main() { + // The API for setting attributes is a little different than the package level + // exported logger. See Godoc. + log.Out = os.Stderr + + log.WithFields(logrus.Fields{ + "animal": "walrus", + "size": 10, + }).Info("A group of walrus emerges from the ocean") +} +``` + +#### Fields + +Logrus encourages careful, structured logging though logging fields instead of +long, unparseable error messages. For example, instead of: `log.Fatalf("Failed +to send event %s to topic %s with key %d")`, you should log the much more +discoverable: + +```go +log.WithFields(log.Fields{ + "event": event, + "topic": topic, + "key": key, +}).Fatal("Failed to send event") +``` + +We've found this API forces you to think about logging in a way that produces +much more useful logging messages. We've been in countless situations where just +a single added field to a log statement that was already there would've saved us +hours. The `WithFields` call is optional. + +In general, with Logrus using any of the `printf`-family functions should be +seen as a hint you should add a field, however, you can still use the +`printf`-family functions with Logrus. + +#### Hooks + +You can add hooks for logging levels. For example to send errors to an exception +tracking service on `Error`, `Fatal` and `Panic`, info to StatsD or log to +multiple places simultaneously, e.g. syslog. + +Logrus comes with [built-in hooks](hooks/). Add those, or your custom hook, in +`init`: + +```go +import ( + log "github.com/Sirupsen/logrus" + "github.com/Sirupsen/logrus/hooks/airbrake" + logrus_syslog "github.com/Sirupsen/logrus/hooks/syslog" + "log/syslog" +) + +func init() { + log.AddHook(airbrake.NewHook("https://example.com", "xyz", "development")) + + hook, err := logrus_syslog.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "") + if err != nil { + log.Error("Unable to connect to local syslog daemon") + } else { + log.AddHook(hook) + } +} +``` + + +| Hook | Description | +| ----- | ----------- | +| [Airbrake](https://github.com/Sirupsen/logrus/blob/master/hooks/airbrake/airbrake.go) | Send errors to an exception tracking service compatible with the Airbrake API. Uses [`airbrake-go`](https://github.com/tobi/airbrake-go) behind the scenes. | +| [Papertrail](https://github.com/Sirupsen/logrus/blob/master/hooks/papertrail/papertrail.go) | Send errors to the Papertrail hosted logging service via UDP. | +| [Syslog](https://github.com/Sirupsen/logrus/blob/master/hooks/syslog/syslog.go) | Send errors to remote syslog server. Uses standard library `log/syslog` behind the scenes. | +| [BugSnag](https://github.com/Sirupsen/logrus/blob/master/hooks/bugsnag/bugsnag.go) | Send errors to the Bugsnag exception tracking service. | +| [Sentry](https://github.com/Sirupsen/logrus/blob/master/hooks/sentry/sentry.go) | Send errors to the Sentry error logging and aggregation service. | +| [Hiprus](https://github.com/nubo/hiprus) | Send errors to a channel in hipchat. | +| [Logrusly](https://github.com/sebest/logrusly) | Send logs to [Loggly](https://www.loggly.com/) | +| [Slackrus](https://github.com/johntdyer/slackrus) | Hook for Slack chat. | +| [Journalhook](https://github.com/wercker/journalhook) | Hook for logging to `systemd-journald` | +| [Graylog](https://github.com/gemnasium/logrus-hooks/tree/master/graylog) | Hook for logging to [Graylog](http://graylog2.org/) | +| [Raygun](https://github.com/squirkle/logrus-raygun-hook) | Hook for logging to [Raygun.io](http://raygun.io/) | +| [LFShook](https://github.com/rifflock/lfshook) | Hook for logging to the local filesystem | +| [Honeybadger](https://github.com/agonzalezro/logrus_honeybadger) | Hook for sending exceptions to Honeybadger | +| [Mail](https://github.com/zbindenren/logrus_mail) | Hook for sending exceptions via mail | +| [Rollrus](https://github.com/heroku/rollrus) | Hook for sending errors to rollbar | +| [Fluentd](https://github.com/evalphobia/logrus_fluent) | Hook for logging to fluentd | +| [Mongodb](https://github.com/weekface/mgorus) | Hook for logging to mongodb | + +#### Level logging + +Logrus has six logging levels: Debug, Info, Warning, Error, Fatal and Panic. + +```go +log.Debug("Useful debugging information.") +log.Info("Something noteworthy happened!") +log.Warn("You should probably take a look at this.") +log.Error("Something failed but I'm not quitting.") +// Calls os.Exit(1) after logging +log.Fatal("Bye.") +// Calls panic() after logging +log.Panic("I'm bailing.") +``` + +You can set the logging level on a `Logger`, then it will only log entries with +that severity or anything above it: + +```go +// Will log anything that is info or above (warn, error, fatal, panic). Default. +log.SetLevel(log.InfoLevel) +``` + +It may be useful to set `log.Level = logrus.DebugLevel` in a debug or verbose +environment if your application has that. + +#### Entries + +Besides the fields added with `WithField` or `WithFields` some fields are +automatically added to all logging events: + +1. `time`. The timestamp when the entry was created. +2. `msg`. The logging message passed to `{Info,Warn,Error,Fatal,Panic}` after + the `AddFields` call. E.g. `Failed to send event.` +3. `level`. The logging level. E.g. `info`. + +#### Environments + +Logrus has no notion of environment. + +If you wish for hooks and formatters to only be used in specific environments, +you should handle that yourself. For example, if your application has a global +variable `Environment`, which is a string representation of the environment you +could do: + +```go +import ( + log "github.com/Sirupsen/logrus" +) + +init() { + // do something here to set environment depending on an environment variable + // or command-line flag + if Environment == "production" { + log.SetFormatter(&log.JSONFormatter{}) + } else { + // The TextFormatter is default, you don't actually have to do this. + log.SetFormatter(&log.TextFormatter{}) + } +} +``` + +This configuration is how `logrus` was intended to be used, but JSON in +production is mostly only useful if you do log aggregation with tools like +Splunk or Logstash. + +#### Formatters + +The built-in logging formatters are: + +* `logrus.TextFormatter`. Logs the event in colors if stdout is a tty, otherwise + without colors. + * *Note:* to force colored output when there is no TTY, set the `ForceColors` + field to `true`. To force no colored output even if there is a TTY set the + `DisableColors` field to `true` +* `logrus.JSONFormatter`. Logs fields as JSON. +* `logrus_logstash.LogstashFormatter`. Logs fields as Logstash Events (http://logstash.net). + + ```go + logrus.SetFormatter(&logrus_logstash.LogstashFormatter{Type: “application_name"}) + ``` + +Third party logging formatters: + +* [`zalgo`](https://github.com/aybabtme/logzalgo): invoking the P͉̫o̳̼̊w̖͈̰͎e̬͔̭͂r͚̼̹̲ ̫͓͉̳͈ō̠͕͖̚f̝͍̠ ͕̲̞͖͑Z̖̫̤̫ͪa͉̬͈̗l͖͎g̳̥o̰̥̅!̣͔̲̻͊̄ ̙̘̦̹̦. + +You can define your formatter by implementing the `Formatter` interface, +requiring a `Format` method. `Format` takes an `*Entry`. `entry.Data` is a +`Fields` type (`map[string]interface{}`) with all your fields as well as the +default ones (see Entries section above): + +```go +type MyJSONFormatter struct { +} + +log.SetFormatter(new(MyJSONFormatter)) + +func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) { + // Note this doesn't include Time, Level and Message which are available on + // the Entry. Consult `godoc` on information about those fields or read the + // source of the official loggers. + serialized, err := json.Marshal(entry.Data) + if err != nil { + return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err) + } + return append(serialized, '\n'), nil +} +``` + +#### Logger as an `io.Writer` + +Logrus can be transformed into an `io.Writer`. That writer is the end of an `io.Pipe` and it is your responsibility to close it. + +```go +w := logger.Writer() +defer w.Close() + +srv := http.Server{ + // create a stdlib log.Logger that writes to + // logrus.Logger. + ErrorLog: log.New(w, "", 0), +} +``` + +Each line written to that writer will be printed the usual way, using formatters +and hooks. The level for those entries is `info`. + +#### Rotation + +Log rotation is not provided with Logrus. Log rotation should be done by an +external program (like `logrotate(8)`) that can compress and delete old log +entries. It should not be a feature of the application-level logger. + + +[godoc]: https://godoc.org/github.com/Sirupsen/logrus diff --git a/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/entry.go b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/entry.go new file mode 100644 index 0000000..04673a0 --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/entry.go @@ -0,0 +1,256 @@ +package logrus + +import ( + "bytes" + "fmt" + "io" + "os" + "time" +) + +// An entry is the final or intermediate Logrus logging entry. It contains all +// the fields passed with WithField{,s}. It's finally logged when Debug, Info, +// Warn, Error, Fatal or Panic is called on it. These objects can be reused and +// passed around as much as you wish to avoid field duplication. +type Entry struct { + Logger *Logger + + // Contains all the fields set by the user. + Data Fields + + // Time at which the log entry was created + Time time.Time + + // Level the log entry was logged at: Debug, Info, Warn, Error, Fatal or Panic + Level Level + + // Message passed to Debug, Info, Warn, Error, Fatal or Panic + Message string +} + +func NewEntry(logger *Logger) *Entry { + return &Entry{ + Logger: logger, + // Default is three fields, give a little extra room + Data: make(Fields, 5), + } +} + +// Returns a reader for the entry, which is a proxy to the formatter. +func (entry *Entry) Reader() (*bytes.Buffer, error) { + serialized, err := entry.Logger.Formatter.Format(entry) + return bytes.NewBuffer(serialized), err +} + +// Returns the string representation from the reader and ultimately the +// formatter. +func (entry *Entry) String() (string, error) { + reader, err := entry.Reader() + if err != nil { + return "", err + } + + return reader.String(), err +} + +// Add a single field to the Entry. +func (entry *Entry) WithField(key string, value interface{}) *Entry { + return entry.WithFields(Fields{key: value}) +} + +// Add a map of fields to the Entry. +func (entry *Entry) WithFields(fields Fields) *Entry { + data := Fields{} + for k, v := range entry.Data { + data[k] = v + } + for k, v := range fields { + data[k] = v + } + return &Entry{Logger: entry.Logger, Data: data} +} + +// This function is not declared with a pointer value because otherwise +// race conditions will occur when using multiple goroutines +func (entry Entry) log(level Level, msg string) { + entry.Time = time.Now() + entry.Level = level + entry.Message = msg + + if err := entry.Logger.Hooks.Fire(level, &entry); err != nil { + entry.Logger.mu.Lock() + fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err) + entry.Logger.mu.Unlock() + } + + reader, err := entry.Reader() + if err != nil { + entry.Logger.mu.Lock() + fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v\n", err) + entry.Logger.mu.Unlock() + } + + entry.Logger.mu.Lock() + defer entry.Logger.mu.Unlock() + + _, err = io.Copy(entry.Logger.Out, reader) + if err != nil { + fmt.Fprintf(os.Stderr, "Failed to write to log, %v\n", err) + } + + // To avoid Entry#log() returning a value that only would make sense for + // panic() to use in Entry#Panic(), we avoid the allocation by checking + // directly here. + if level <= PanicLevel { + panic(&entry) + } +} + +func (entry *Entry) Debug(args ...interface{}) { + if entry.Logger.Level >= DebugLevel { + entry.log(DebugLevel, fmt.Sprint(args...)) + } +} + +func (entry *Entry) Print(args ...interface{}) { + entry.Info(args...) +} + +func (entry *Entry) Info(args ...interface{}) { + if entry.Logger.Level >= InfoLevel { + entry.log(InfoLevel, fmt.Sprint(args...)) + } +} + +func (entry *Entry) Warn(args ...interface{}) { + if entry.Logger.Level >= WarnLevel { + entry.log(WarnLevel, fmt.Sprint(args...)) + } +} + +func (entry *Entry) Warning(args ...interface{}) { + entry.Warn(args...) +} + +func (entry *Entry) Error(args ...interface{}) { + if entry.Logger.Level >= ErrorLevel { + entry.log(ErrorLevel, fmt.Sprint(args...)) + } +} + +func (entry *Entry) Fatal(args ...interface{}) { + if entry.Logger.Level >= FatalLevel { + entry.log(FatalLevel, fmt.Sprint(args...)) + } + os.Exit(1) +} + +func (entry *Entry) Panic(args ...interface{}) { + if entry.Logger.Level >= PanicLevel { + entry.log(PanicLevel, fmt.Sprint(args...)) + } + panic(fmt.Sprint(args...)) +} + +// Entry Printf family functions + +func (entry *Entry) Debugf(format string, args ...interface{}) { + if entry.Logger.Level >= DebugLevel { + entry.Debug(fmt.Sprintf(format, args...)) + } +} + +func (entry *Entry) Infof(format string, args ...interface{}) { + if entry.Logger.Level >= InfoLevel { + entry.Info(fmt.Sprintf(format, args...)) + } +} + +func (entry *Entry) Printf(format string, args ...interface{}) { + entry.Infof(format, args...) +} + +func (entry *Entry) Warnf(format string, args ...interface{}) { + if entry.Logger.Level >= WarnLevel { + entry.Warn(fmt.Sprintf(format, args...)) + } +} + +func (entry *Entry) Warningf(format string, args ...interface{}) { + entry.Warnf(format, args...) +} + +func (entry *Entry) Errorf(format string, args ...interface{}) { + if entry.Logger.Level >= ErrorLevel { + entry.Error(fmt.Sprintf(format, args...)) + } +} + +func (entry *Entry) Fatalf(format string, args ...interface{}) { + if entry.Logger.Level >= FatalLevel { + entry.Fatal(fmt.Sprintf(format, args...)) + } + os.Exit(1) +} + +func (entry *Entry) Panicf(format string, args ...interface{}) { + if entry.Logger.Level >= PanicLevel { + entry.Panic(fmt.Sprintf(format, args...)) + } +} + +// Entry Println family functions + +func (entry *Entry) Debugln(args ...interface{}) { + if entry.Logger.Level >= DebugLevel { + entry.Debug(entry.sprintlnn(args...)) + } +} + +func (entry *Entry) Infoln(args ...interface{}) { + if entry.Logger.Level >= InfoLevel { + entry.Info(entry.sprintlnn(args...)) + } +} + +func (entry *Entry) Println(args ...interface{}) { + entry.Infoln(args...) +} + +func (entry *Entry) Warnln(args ...interface{}) { + if entry.Logger.Level >= WarnLevel { + entry.Warn(entry.sprintlnn(args...)) + } +} + +func (entry *Entry) Warningln(args ...interface{}) { + entry.Warnln(args...) +} + +func (entry *Entry) Errorln(args ...interface{}) { + if entry.Logger.Level >= ErrorLevel { + entry.Error(entry.sprintlnn(args...)) + } +} + +func (entry *Entry) Fatalln(args ...interface{}) { + if entry.Logger.Level >= FatalLevel { + entry.Fatal(entry.sprintlnn(args...)) + } + os.Exit(1) +} + +func (entry *Entry) Panicln(args ...interface{}) { + if entry.Logger.Level >= PanicLevel { + entry.Panic(entry.sprintlnn(args...)) + } +} + +// Sprintlnn => Sprint no newline. This is to get the behavior of how +// fmt.Sprintln where spaces are always added between operands, regardless of +// their type. Instead of vendoring the Sprintln implementation to spare a +// string allocation, we do the simplest thing. +func (entry *Entry) sprintlnn(args ...interface{}) string { + msg := fmt.Sprintln(args...) + return msg[:len(msg)-1] +} diff --git a/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/entry_test.go b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/entry_test.go new file mode 100644 index 0000000..98717df --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/entry_test.go @@ -0,0 +1,53 @@ +package logrus + +import ( + "bytes" + "fmt" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestEntryPanicln(t *testing.T) { + errBoom := fmt.Errorf("boom time") + + defer func() { + p := recover() + assert.NotNil(t, p) + + switch pVal := p.(type) { + case *Entry: + assert.Equal(t, "kaboom", pVal.Message) + assert.Equal(t, errBoom, pVal.Data["err"]) + default: + t.Fatalf("want type *Entry, got %T: %#v", pVal, pVal) + } + }() + + logger := New() + logger.Out = &bytes.Buffer{} + entry := NewEntry(logger) + entry.WithField("err", errBoom).Panicln("kaboom") +} + +func TestEntryPanicf(t *testing.T) { + errBoom := fmt.Errorf("boom again") + + defer func() { + p := recover() + assert.NotNil(t, p) + + switch pVal := p.(type) { + case *Entry: + assert.Equal(t, "kaboom true", pVal.Message) + assert.Equal(t, errBoom, pVal.Data["err"]) + default: + t.Fatalf("want type *Entry, got %T: %#v", pVal, pVal) + } + }() + + logger := New() + logger.Out = &bytes.Buffer{} + entry := NewEntry(logger) + entry.WithField("err", errBoom).Panicf("kaboom %v", true) +} diff --git a/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/examples/basic/basic.go b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/examples/basic/basic.go new file mode 100644 index 0000000..a1623ec --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/examples/basic/basic.go @@ -0,0 +1,50 @@ +package main + +import ( + "github.com/Sirupsen/logrus" +) + +var log = logrus.New() + +func init() { + log.Formatter = new(logrus.JSONFormatter) + log.Formatter = new(logrus.TextFormatter) // default + log.Level = logrus.DebugLevel +} + +func main() { + defer func() { + err := recover() + if err != nil { + log.WithFields(logrus.Fields{ + "omg": true, + "err": err, + "number": 100, + }).Fatal("The ice breaks!") + } + }() + + log.WithFields(logrus.Fields{ + "animal": "walrus", + "number": 8, + }).Debug("Started observing beach") + + log.WithFields(logrus.Fields{ + "animal": "walrus", + "size": 10, + }).Info("A group of walrus emerges from the ocean") + + log.WithFields(logrus.Fields{ + "omg": true, + "number": 122, + }).Warn("The group's number increased tremendously!") + + log.WithFields(logrus.Fields{ + "temperature": -4, + }).Debug("Temperature changes") + + log.WithFields(logrus.Fields{ + "animal": "orca", + "size": 9009, + }).Panic("It's over 9000!") +} diff --git a/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/examples/hook/hook.go b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/examples/hook/hook.go new file mode 100644 index 0000000..cb5759a --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/examples/hook/hook.go @@ -0,0 +1,30 @@ +package main + +import ( + "github.com/Sirupsen/logrus" + "github.com/Sirupsen/logrus/hooks/airbrake" +) + +var log = logrus.New() + +func init() { + log.Formatter = new(logrus.TextFormatter) // default + log.Hooks.Add(airbrake.NewHook("https://example.com", "xyz", "development")) +} + +func main() { + log.WithFields(logrus.Fields{ + "animal": "walrus", + "size": 10, + }).Info("A group of walrus emerges from the ocean") + + log.WithFields(logrus.Fields{ + "omg": true, + "number": 122, + }).Warn("The group's number increased tremendously!") + + log.WithFields(logrus.Fields{ + "omg": true, + "number": 100, + }).Fatal("The ice breaks!") +} diff --git a/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/exported.go b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/exported.go new file mode 100644 index 0000000..a67e1b8 --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/exported.go @@ -0,0 +1,188 @@ +package logrus + +import ( + "io" +) + +var ( + // std is the name of the standard logger in stdlib `log` + std = New() +) + +func StandardLogger() *Logger { + return std +} + +// SetOutput sets the standard logger output. +func SetOutput(out io.Writer) { + std.mu.Lock() + defer std.mu.Unlock() + std.Out = out +} + +// SetFormatter sets the standard logger formatter. +func SetFormatter(formatter Formatter) { + std.mu.Lock() + defer std.mu.Unlock() + std.Formatter = formatter +} + +// SetLevel sets the standard logger level. +func SetLevel(level Level) { + std.mu.Lock() + defer std.mu.Unlock() + std.Level = level +} + +// GetLevel returns the standard logger level. +func GetLevel() Level { + std.mu.Lock() + defer std.mu.Unlock() + return std.Level +} + +// AddHook adds a hook to the standard logger hooks. +func AddHook(hook Hook) { + std.mu.Lock() + defer std.mu.Unlock() + std.Hooks.Add(hook) +} + +// WithField creates an entry from the standard logger and adds a field to +// it. If you want multiple fields, use `WithFields`. +// +// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal +// or Panic on the Entry it returns. +func WithField(key string, value interface{}) *Entry { + return std.WithField(key, value) +} + +// WithFields creates an entry from the standard logger and adds multiple +// fields to it. This is simply a helper for `WithField`, invoking it +// once for each field. +// +// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal +// or Panic on the Entry it returns. +func WithFields(fields Fields) *Entry { + return std.WithFields(fields) +} + +// Debug logs a message at level Debug on the standard logger. +func Debug(args ...interface{}) { + std.Debug(args...) +} + +// Print logs a message at level Info on the standard logger. +func Print(args ...interface{}) { + std.Print(args...) +} + +// Info logs a message at level Info on the standard logger. +func Info(args ...interface{}) { + std.Info(args...) +} + +// Warn logs a message at level Warn on the standard logger. +func Warn(args ...interface{}) { + std.Warn(args...) +} + +// Warning logs a message at level Warn on the standard logger. +func Warning(args ...interface{}) { + std.Warning(args...) +} + +// Error logs a message at level Error on the standard logger. +func Error(args ...interface{}) { + std.Error(args...) +} + +// Panic logs a message at level Panic on the standard logger. +func Panic(args ...interface{}) { + std.Panic(args...) +} + +// Fatal logs a message at level Fatal on the standard logger. +func Fatal(args ...interface{}) { + std.Fatal(args...) +} + +// Debugf logs a message at level Debug on the standard logger. +func Debugf(format string, args ...interface{}) { + std.Debugf(format, args...) +} + +// Printf logs a message at level Info on the standard logger. +func Printf(format string, args ...interface{}) { + std.Printf(format, args...) +} + +// Infof logs a message at level Info on the standard logger. +func Infof(format string, args ...interface{}) { + std.Infof(format, args...) +} + +// Warnf logs a message at level Warn on the standard logger. +func Warnf(format string, args ...interface{}) { + std.Warnf(format, args...) +} + +// Warningf logs a message at level Warn on the standard logger. +func Warningf(format string, args ...interface{}) { + std.Warningf(format, args...) +} + +// Errorf logs a message at level Error on the standard logger. +func Errorf(format string, args ...interface{}) { + std.Errorf(format, args...) +} + +// Panicf logs a message at level Panic on the standard logger. +func Panicf(format string, args ...interface{}) { + std.Panicf(format, args...) +} + +// Fatalf logs a message at level Fatal on the standard logger. +func Fatalf(format string, args ...interface{}) { + std.Fatalf(format, args...) +} + +// Debugln logs a message at level Debug on the standard logger. +func Debugln(args ...interface{}) { + std.Debugln(args...) +} + +// Println logs a message at level Info on the standard logger. +func Println(args ...interface{}) { + std.Println(args...) +} + +// Infoln logs a message at level Info on the standard logger. +func Infoln(args ...interface{}) { + std.Infoln(args...) +} + +// Warnln logs a message at level Warn on the standard logger. +func Warnln(args ...interface{}) { + std.Warnln(args...) +} + +// Warningln logs a message at level Warn on the standard logger. +func Warningln(args ...interface{}) { + std.Warningln(args...) +} + +// Errorln logs a message at level Error on the standard logger. +func Errorln(args ...interface{}) { + std.Errorln(args...) +} + +// Panicln logs a message at level Panic on the standard logger. +func Panicln(args ...interface{}) { + std.Panicln(args...) +} + +// Fatalln logs a message at level Fatal on the standard logger. +func Fatalln(args ...interface{}) { + std.Fatalln(args...) +} diff --git a/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/formatter.go b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/formatter.go new file mode 100644 index 0000000..104d689 --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/formatter.go @@ -0,0 +1,48 @@ +package logrus + +import "time" + +const DefaultTimestampFormat = time.RFC3339 + +// The Formatter interface is used to implement a custom Formatter. It takes an +// `Entry`. It exposes all the fields, including the default ones: +// +// * `entry.Data["msg"]`. The message passed from Info, Warn, Error .. +// * `entry.Data["time"]`. The timestamp. +// * `entry.Data["level"]. The level the entry was logged at. +// +// Any additional fields added with `WithField` or `WithFields` are also in +// `entry.Data`. Format is expected to return an array of bytes which are then +// logged to `logger.Out`. +type Formatter interface { + Format(*Entry) ([]byte, error) +} + +// This is to not silently overwrite `time`, `msg` and `level` fields when +// dumping it. If this code wasn't there doing: +// +// logrus.WithField("level", 1).Info("hello") +// +// Would just silently drop the user provided level. Instead with this code +// it'll logged as: +// +// {"level": "info", "fields.level": 1, "msg": "hello", "time": "..."} +// +// It's not exported because it's still using Data in an opinionated way. It's to +// avoid code duplication between the two default formatters. +func prefixFieldClashes(data Fields) { + _, ok := data["time"] + if ok { + data["fields.time"] = data["time"] + } + + _, ok = data["msg"] + if ok { + data["fields.msg"] = data["msg"] + } + + _, ok = data["level"] + if ok { + data["fields.level"] = data["level"] + } +} diff --git a/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/formatter_bench_test.go b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/formatter_bench_test.go new file mode 100644 index 0000000..c6d290c --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/formatter_bench_test.go @@ -0,0 +1,98 @@ +package logrus + +import ( + "fmt" + "testing" + "time" +) + +// smallFields is a small size data set for benchmarking +var smallFields = Fields{ + "foo": "bar", + "baz": "qux", + "one": "two", + "three": "four", +} + +// largeFields is a large size data set for benchmarking +var largeFields = Fields{ + "foo": "bar", + "baz": "qux", + "one": "two", + "three": "four", + "five": "six", + "seven": "eight", + "nine": "ten", + "eleven": "twelve", + "thirteen": "fourteen", + "fifteen": "sixteen", + "seventeen": "eighteen", + "nineteen": "twenty", + "a": "b", + "c": "d", + "e": "f", + "g": "h", + "i": "j", + "k": "l", + "m": "n", + "o": "p", + "q": "r", + "s": "t", + "u": "v", + "w": "x", + "y": "z", + "this": "will", + "make": "thirty", + "entries": "yeah", +} + +var errorFields = Fields{ + "foo": fmt.Errorf("bar"), + "baz": fmt.Errorf("qux"), +} + +func BenchmarkErrorTextFormatter(b *testing.B) { + doBenchmark(b, &TextFormatter{DisableColors: true}, errorFields) +} + +func BenchmarkSmallTextFormatter(b *testing.B) { + doBenchmark(b, &TextFormatter{DisableColors: true}, smallFields) +} + +func BenchmarkLargeTextFormatter(b *testing.B) { + doBenchmark(b, &TextFormatter{DisableColors: true}, largeFields) +} + +func BenchmarkSmallColoredTextFormatter(b *testing.B) { + doBenchmark(b, &TextFormatter{ForceColors: true}, smallFields) +} + +func BenchmarkLargeColoredTextFormatter(b *testing.B) { + doBenchmark(b, &TextFormatter{ForceColors: true}, largeFields) +} + +func BenchmarkSmallJSONFormatter(b *testing.B) { + doBenchmark(b, &JSONFormatter{}, smallFields) +} + +func BenchmarkLargeJSONFormatter(b *testing.B) { + doBenchmark(b, &JSONFormatter{}, largeFields) +} + +func doBenchmark(b *testing.B, formatter Formatter, fields Fields) { + entry := &Entry{ + Time: time.Time{}, + Level: InfoLevel, + Message: "message", + Data: fields, + } + var d []byte + var err error + for i := 0; i < b.N; i++ { + d, err = formatter.Format(entry) + if err != nil { + b.Fatal(err) + } + b.SetBytes(int64(len(d))) + } +} diff --git a/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/formatters/logstash/logstash.go b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/formatters/logstash/logstash.go new file mode 100644 index 0000000..8ea93dd --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/formatters/logstash/logstash.go @@ -0,0 +1,56 @@ +package logstash + +import ( + "encoding/json" + "fmt" + + "github.com/Sirupsen/logrus" +) + +// Formatter generates json in logstash format. +// Logstash site: http://logstash.net/ +type LogstashFormatter struct { + Type string // if not empty use for logstash type field. + + // TimestampFormat sets the format used for timestamps. + TimestampFormat string +} + +func (f *LogstashFormatter) Format(entry *logrus.Entry) ([]byte, error) { + entry.Data["@version"] = 1 + + if f.TimestampFormat == "" { + f.TimestampFormat = logrus.DefaultTimestampFormat + } + + entry.Data["@timestamp"] = entry.Time.Format(f.TimestampFormat) + + // set message field + v, ok := entry.Data["message"] + if ok { + entry.Data["fields.message"] = v + } + entry.Data["message"] = entry.Message + + // set level field + v, ok = entry.Data["level"] + if ok { + entry.Data["fields.level"] = v + } + entry.Data["level"] = entry.Level.String() + + // set type field + if f.Type != "" { + v, ok = entry.Data["type"] + if ok { + entry.Data["fields.type"] = v + } + entry.Data["type"] = f.Type + } + + serialized, err := json.Marshal(entry.Data) + if err != nil { + return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err) + } + return append(serialized, '\n'), nil +} diff --git a/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/formatters/logstash/logstash_test.go b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/formatters/logstash/logstash_test.go new file mode 100644 index 0000000..d8814a0 --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/formatters/logstash/logstash_test.go @@ -0,0 +1,52 @@ +package logstash + +import ( + "bytes" + "encoding/json" + "github.com/Sirupsen/logrus" + "github.com/stretchr/testify/assert" + "testing" +) + +func TestLogstashFormatter(t *testing.T) { + assert := assert.New(t) + + lf := LogstashFormatter{Type: "abc"} + + fields := logrus.Fields{ + "message": "def", + "level": "ijk", + "type": "lmn", + "one": 1, + "pi": 3.14, + "bool": true, + } + + entry := logrus.WithFields(fields) + entry.Message = "msg" + entry.Level = logrus.InfoLevel + + b, _ := lf.Format(entry) + + var data map[string]interface{} + dec := json.NewDecoder(bytes.NewReader(b)) + dec.UseNumber() + dec.Decode(&data) + + // base fields + assert.Equal(json.Number("1"), data["@version"]) + assert.NotEmpty(data["@timestamp"]) + assert.Equal("abc", data["type"]) + assert.Equal("msg", data["message"]) + assert.Equal("info", data["level"]) + + // substituted fields + assert.Equal("def", data["fields.message"]) + assert.Equal("ijk", data["fields.level"]) + assert.Equal("lmn", data["fields.type"]) + + // formats + assert.Equal(json.Number("1"), data["one"]) + assert.Equal(json.Number("3.14"), data["pi"]) + assert.Equal(true, data["bool"]) +} diff --git a/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/hook_test.go b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/hook_test.go new file mode 100644 index 0000000..13f34cb --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/hook_test.go @@ -0,0 +1,122 @@ +package logrus + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +type TestHook struct { + Fired bool +} + +func (hook *TestHook) Fire(entry *Entry) error { + hook.Fired = true + return nil +} + +func (hook *TestHook) Levels() []Level { + return []Level{ + DebugLevel, + InfoLevel, + WarnLevel, + ErrorLevel, + FatalLevel, + PanicLevel, + } +} + +func TestHookFires(t *testing.T) { + hook := new(TestHook) + + LogAndAssertJSON(t, func(log *Logger) { + log.Hooks.Add(hook) + assert.Equal(t, hook.Fired, false) + + log.Print("test") + }, func(fields Fields) { + assert.Equal(t, hook.Fired, true) + }) +} + +type ModifyHook struct { +} + +func (hook *ModifyHook) Fire(entry *Entry) error { + entry.Data["wow"] = "whale" + return nil +} + +func (hook *ModifyHook) Levels() []Level { + return []Level{ + DebugLevel, + InfoLevel, + WarnLevel, + ErrorLevel, + FatalLevel, + PanicLevel, + } +} + +func TestHookCanModifyEntry(t *testing.T) { + hook := new(ModifyHook) + + LogAndAssertJSON(t, func(log *Logger) { + log.Hooks.Add(hook) + log.WithField("wow", "elephant").Print("test") + }, func(fields Fields) { + assert.Equal(t, fields["wow"], "whale") + }) +} + +func TestCanFireMultipleHooks(t *testing.T) { + hook1 := new(ModifyHook) + hook2 := new(TestHook) + + LogAndAssertJSON(t, func(log *Logger) { + log.Hooks.Add(hook1) + log.Hooks.Add(hook2) + + log.WithField("wow", "elephant").Print("test") + }, func(fields Fields) { + assert.Equal(t, fields["wow"], "whale") + assert.Equal(t, hook2.Fired, true) + }) +} + +type ErrorHook struct { + Fired bool +} + +func (hook *ErrorHook) Fire(entry *Entry) error { + hook.Fired = true + return nil +} + +func (hook *ErrorHook) Levels() []Level { + return []Level{ + ErrorLevel, + } +} + +func TestErrorHookShouldntFireOnInfo(t *testing.T) { + hook := new(ErrorHook) + + LogAndAssertJSON(t, func(log *Logger) { + log.Hooks.Add(hook) + log.Info("test") + }, func(fields Fields) { + assert.Equal(t, hook.Fired, false) + }) +} + +func TestErrorHookShouldFireOnError(t *testing.T) { + hook := new(ErrorHook) + + LogAndAssertJSON(t, func(log *Logger) { + log.Hooks.Add(hook) + log.Error("test") + }, func(fields Fields) { + assert.Equal(t, hook.Fired, true) + }) +} diff --git a/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/hooks.go b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/hooks.go new file mode 100644 index 0000000..3f151cd --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/hooks.go @@ -0,0 +1,34 @@ +package logrus + +// A hook to be fired when logging on the logging levels returned from +// `Levels()` on your implementation of the interface. Note that this is not +// fired in a goroutine or a channel with workers, you should handle such +// functionality yourself if your call is non-blocking and you don't wish for +// the logging calls for levels returned from `Levels()` to block. +type Hook interface { + Levels() []Level + Fire(*Entry) error +} + +// Internal type for storing the hooks on a logger instance. +type LevelHooks map[Level][]Hook + +// Add a hook to an instance of logger. This is called with +// `log.Hooks.Add(new(MyHook))` where `MyHook` implements the `Hook` interface. +func (hooks LevelHooks) Add(hook Hook) { + for _, level := range hook.Levels() { + hooks[level] = append(hooks[level], hook) + } +} + +// Fire all the hooks for the passed level. Used by `entry.log` to fire +// appropriate hooks for a log entry. +func (hooks LevelHooks) Fire(level Level, entry *Entry) error { + for _, hook := range hooks[level] { + if err := hook.Fire(entry); err != nil { + return err + } + } + + return nil +} diff --git a/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/hooks/airbrake/airbrake.go b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/hooks/airbrake/airbrake.go new file mode 100644 index 0000000..b0502c3 --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/hooks/airbrake/airbrake.go @@ -0,0 +1,54 @@ +package airbrake + +import ( + "errors" + "fmt" + + "github.com/Sirupsen/logrus" + "github.com/tobi/airbrake-go" +) + +// AirbrakeHook to send exceptions to an exception-tracking service compatible +// with the Airbrake API. +type airbrakeHook struct { + APIKey string + Endpoint string + Environment string +} + +func NewHook(endpoint, apiKey, env string) *airbrakeHook { + return &airbrakeHook{ + APIKey: apiKey, + Endpoint: endpoint, + Environment: env, + } +} + +func (hook *airbrakeHook) Fire(entry *logrus.Entry) error { + airbrake.ApiKey = hook.APIKey + airbrake.Endpoint = hook.Endpoint + airbrake.Environment = hook.Environment + + var notifyErr error + err, ok := entry.Data["error"].(error) + if ok { + notifyErr = err + } else { + notifyErr = errors.New(entry.Message) + } + + airErr := airbrake.Notify(notifyErr) + if airErr != nil { + return fmt.Errorf("Failed to send error to Airbrake: %s", airErr) + } + + return nil +} + +func (hook *airbrakeHook) Levels() []logrus.Level { + return []logrus.Level{ + logrus.ErrorLevel, + logrus.FatalLevel, + logrus.PanicLevel, + } +} diff --git a/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/hooks/airbrake/airbrake_test.go b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/hooks/airbrake/airbrake_test.go new file mode 100644 index 0000000..058a91e --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/hooks/airbrake/airbrake_test.go @@ -0,0 +1,133 @@ +package airbrake + +import ( + "encoding/xml" + "net/http" + "net/http/httptest" + "testing" + "time" + + "github.com/Sirupsen/logrus" +) + +type notice struct { + Error NoticeError `xml:"error"` +} +type NoticeError struct { + Class string `xml:"class"` + Message string `xml:"message"` +} + +type customErr struct { + msg string +} + +func (e *customErr) Error() string { + return e.msg +} + +const ( + testAPIKey = "abcxyz" + testEnv = "development" + expectedClass = "*airbrake.customErr" + expectedMsg = "foo" + unintendedMsg = "Airbrake will not see this string" +) + +var ( + noticeError = make(chan NoticeError, 1) +) + +// TestLogEntryMessageReceived checks if invoking Logrus' log.Error +// method causes an XML payload containing the log entry message is received +// by a HTTP server emulating an Airbrake-compatible endpoint. +func TestLogEntryMessageReceived(t *testing.T) { + log := logrus.New() + ts := startAirbrakeServer(t) + defer ts.Close() + + hook := NewHook(ts.URL, testAPIKey, "production") + log.Hooks.Add(hook) + + log.Error(expectedMsg) + + select { + case received := <-noticeError: + if received.Message != expectedMsg { + t.Errorf("Unexpected message received: %s", received.Message) + } + case <-time.After(time.Second): + t.Error("Timed out; no notice received by Airbrake API") + } +} + +// TestLogEntryMessageReceived confirms that, when passing an error type using +// logrus.Fields, a HTTP server emulating an Airbrake endpoint receives the +// error message returned by the Error() method on the error interface +// rather than the logrus.Entry.Message string. +func TestLogEntryWithErrorReceived(t *testing.T) { + log := logrus.New() + ts := startAirbrakeServer(t) + defer ts.Close() + + hook := NewHook(ts.URL, testAPIKey, "production") + log.Hooks.Add(hook) + + log.WithFields(logrus.Fields{ + "error": &customErr{expectedMsg}, + }).Error(unintendedMsg) + + select { + case received := <-noticeError: + if received.Message != expectedMsg { + t.Errorf("Unexpected message received: %s", received.Message) + } + if received.Class != expectedClass { + t.Errorf("Unexpected error class: %s", received.Class) + } + case <-time.After(time.Second): + t.Error("Timed out; no notice received by Airbrake API") + } +} + +// TestLogEntryWithNonErrorTypeNotReceived confirms that, when passing a +// non-error type using logrus.Fields, a HTTP server emulating an Airbrake +// endpoint receives the logrus.Entry.Message string. +// +// Only error types are supported when setting the 'error' field using +// logrus.WithFields(). +func TestLogEntryWithNonErrorTypeNotReceived(t *testing.T) { + log := logrus.New() + ts := startAirbrakeServer(t) + defer ts.Close() + + hook := NewHook(ts.URL, testAPIKey, "production") + log.Hooks.Add(hook) + + log.WithFields(logrus.Fields{ + "error": expectedMsg, + }).Error(unintendedMsg) + + select { + case received := <-noticeError: + if received.Message != unintendedMsg { + t.Errorf("Unexpected message received: %s", received.Message) + } + case <-time.After(time.Second): + t.Error("Timed out; no notice received by Airbrake API") + } +} + +func startAirbrakeServer(t *testing.T) *httptest.Server { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + var notice notice + if err := xml.NewDecoder(r.Body).Decode(¬ice); err != nil { + t.Error(err) + } + r.Body.Close() + + noticeError <- notice.Error + })) + + return ts +} diff --git a/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/hooks/bugsnag/bugsnag.go b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/hooks/bugsnag/bugsnag.go new file mode 100644 index 0000000..d20a0f5 --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/hooks/bugsnag/bugsnag.go @@ -0,0 +1,68 @@ +package logrus_bugsnag + +import ( + "errors" + + "github.com/Sirupsen/logrus" + "github.com/bugsnag/bugsnag-go" +) + +type bugsnagHook struct{} + +// ErrBugsnagUnconfigured is returned if NewBugsnagHook is called before +// bugsnag.Configure. Bugsnag must be configured before the hook. +var ErrBugsnagUnconfigured = errors.New("bugsnag must be configured before installing this logrus hook") + +// ErrBugsnagSendFailed indicates that the hook failed to submit an error to +// bugsnag. The error was successfully generated, but `bugsnag.Notify()` +// failed. +type ErrBugsnagSendFailed struct { + err error +} + +func (e ErrBugsnagSendFailed) Error() string { + return "failed to send error to Bugsnag: " + e.err.Error() +} + +// NewBugsnagHook initializes a logrus hook which sends exceptions to an +// exception-tracking service compatible with the Bugsnag API. Before using +// this hook, you must call bugsnag.Configure(). The returned object should be +// registered with a log via `AddHook()` +// +// Entries that trigger an Error, Fatal or Panic should now include an "error" +// field to send to Bugsnag. +func NewBugsnagHook() (*bugsnagHook, error) { + if bugsnag.Config.APIKey == "" { + return nil, ErrBugsnagUnconfigured + } + return &bugsnagHook{}, nil +} + +// Fire forwards an error to Bugsnag. Given a logrus.Entry, it extracts the +// "error" field (or the Message if the error isn't present) and sends it off. +func (hook *bugsnagHook) Fire(entry *logrus.Entry) error { + var notifyErr error + err, ok := entry.Data["error"].(error) + if ok { + notifyErr = err + } else { + notifyErr = errors.New(entry.Message) + } + + bugsnagErr := bugsnag.Notify(notifyErr) + if bugsnagErr != nil { + return ErrBugsnagSendFailed{bugsnagErr} + } + + return nil +} + +// Levels enumerates the log levels on which the error should be forwarded to +// bugsnag: everything at or above the "Error" level. +func (hook *bugsnagHook) Levels() []logrus.Level { + return []logrus.Level{ + logrus.ErrorLevel, + logrus.FatalLevel, + logrus.PanicLevel, + } +} diff --git a/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/hooks/bugsnag/bugsnag_test.go b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/hooks/bugsnag/bugsnag_test.go new file mode 100644 index 0000000..e9ea298 --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/hooks/bugsnag/bugsnag_test.go @@ -0,0 +1,64 @@ +package logrus_bugsnag + +import ( + "encoding/json" + "errors" + "io/ioutil" + "net/http" + "net/http/httptest" + "testing" + "time" + + "github.com/Sirupsen/logrus" + "github.com/bugsnag/bugsnag-go" +) + +type notice struct { + Events []struct { + Exceptions []struct { + Message string `json:"message"` + } `json:"exceptions"` + } `json:"events"` +} + +func TestNoticeReceived(t *testing.T) { + msg := make(chan string, 1) + expectedMsg := "foo" + + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + var notice notice + data, _ := ioutil.ReadAll(r.Body) + if err := json.Unmarshal(data, ¬ice); err != nil { + t.Error(err) + } + _ = r.Body.Close() + + msg <- notice.Events[0].Exceptions[0].Message + })) + defer ts.Close() + + hook := &bugsnagHook{} + + bugsnag.Configure(bugsnag.Configuration{ + Endpoint: ts.URL, + ReleaseStage: "production", + APIKey: "12345678901234567890123456789012", + Synchronous: true, + }) + + log := logrus.New() + log.Hooks.Add(hook) + + log.WithFields(logrus.Fields{ + "error": errors.New(expectedMsg), + }).Error("Bugsnag will not see this string") + + select { + case received := <-msg: + if received != expectedMsg { + t.Errorf("Unexpected message received: %s", received) + } + case <-time.After(time.Second): + t.Error("Timed out; no notice received by Bugsnag API") + } +} diff --git a/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/hooks/papertrail/README.md b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/hooks/papertrail/README.md new file mode 100644 index 0000000..ae61e92 --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/hooks/papertrail/README.md @@ -0,0 +1,28 @@ +# Papertrail Hook for Logrus :walrus: + +[Papertrail](https://papertrailapp.com) provides hosted log management. Once stored in Papertrail, you can [group](http://help.papertrailapp.com/kb/how-it-works/groups/) your logs on various dimensions, [search](http://help.papertrailapp.com/kb/how-it-works/search-syntax) them, and trigger [alerts](http://help.papertrailapp.com/kb/how-it-works/alerts). + +In most deployments, you'll want to send logs to Papertrail via their [remote_syslog](http://help.papertrailapp.com/kb/configuration/configuring-centralized-logging-from-text-log-files-in-unix/) daemon, which requires no application-specific configuration. This hook is intended for relatively low-volume logging, likely in managed cloud hosting deployments where installing `remote_syslog` is not possible. + +## Usage + +You can find your Papertrail UDP port on your [Papertrail account page](https://papertrailapp.com/account/destinations). Substitute it below for `YOUR_PAPERTRAIL_UDP_PORT`. + +For `YOUR_APP_NAME`, substitute a short string that will readily identify your application or service in the logs. + +```go +import ( + "log/syslog" + "github.com/Sirupsen/logrus" + "github.com/Sirupsen/logrus/hooks/papertrail" +) + +func main() { + log := logrus.New() + hook, err := logrus_papertrail.NewPapertrailHook("logs.papertrailapp.com", YOUR_PAPERTRAIL_UDP_PORT, YOUR_APP_NAME) + + if err == nil { + log.Hooks.Add(hook) + } +} +``` diff --git a/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/hooks/papertrail/papertrail.go b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/hooks/papertrail/papertrail.go new file mode 100644 index 0000000..c0f10c1 --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/hooks/papertrail/papertrail.go @@ -0,0 +1,55 @@ +package logrus_papertrail + +import ( + "fmt" + "net" + "os" + "time" + + "github.com/Sirupsen/logrus" +) + +const ( + format = "Jan 2 15:04:05" +) + +// PapertrailHook to send logs to a logging service compatible with the Papertrail API. +type PapertrailHook struct { + Host string + Port int + AppName string + UDPConn net.Conn +} + +// NewPapertrailHook creates a hook to be added to an instance of logger. +func NewPapertrailHook(host string, port int, appName string) (*PapertrailHook, error) { + conn, err := net.Dial("udp", fmt.Sprintf("%s:%d", host, port)) + return &PapertrailHook{host, port, appName, conn}, err +} + +// Fire is called when a log event is fired. +func (hook *PapertrailHook) Fire(entry *logrus.Entry) error { + date := time.Now().Format(format) + msg, _ := entry.String() + payload := fmt.Sprintf("<22> %s %s: %s", date, hook.AppName, msg) + + bytesWritten, err := hook.UDPConn.Write([]byte(payload)) + if err != nil { + fmt.Fprintf(os.Stderr, "Unable to send log line to Papertrail via UDP. Wrote %d bytes before error: %v", bytesWritten, err) + return err + } + + return nil +} + +// Levels returns the available logging levels. +func (hook *PapertrailHook) Levels() []logrus.Level { + return []logrus.Level{ + logrus.PanicLevel, + logrus.FatalLevel, + logrus.ErrorLevel, + logrus.WarnLevel, + logrus.InfoLevel, + logrus.DebugLevel, + } +} diff --git a/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/hooks/papertrail/papertrail_test.go b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/hooks/papertrail/papertrail_test.go new file mode 100644 index 0000000..96318d0 --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/hooks/papertrail/papertrail_test.go @@ -0,0 +1,26 @@ +package logrus_papertrail + +import ( + "fmt" + "testing" + + "github.com/Sirupsen/logrus" + "github.com/stvp/go-udp-testing" +) + +func TestWritingToUDP(t *testing.T) { + port := 16661 + udp.SetAddr(fmt.Sprintf(":%d", port)) + + hook, err := NewPapertrailHook("localhost", port, "test") + if err != nil { + t.Errorf("Unable to connect to local UDP server.") + } + + log := logrus.New() + log.Hooks.Add(hook) + + udp.ShouldReceive(t, "foo", func() { + log.Info("foo") + }) +} diff --git a/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/hooks/sentry/README.md b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/hooks/sentry/README.md new file mode 100644 index 0000000..31de654 --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/hooks/sentry/README.md @@ -0,0 +1,111 @@ +# Sentry Hook for Logrus :walrus: + +[Sentry](https://getsentry.com) provides both self-hosted and hosted +solutions for exception tracking. +Both client and server are +[open source](https://github.com/getsentry/sentry). + +## Usage + +Every sentry application defined on the server gets a different +[DSN](https://www.getsentry.com/docs/). In the example below replace +`YOUR_DSN` with the one created for your application. + +```go +import ( + "github.com/Sirupsen/logrus" + "github.com/Sirupsen/logrus/hooks/sentry" +) + +func main() { + log := logrus.New() + hook, err := logrus_sentry.NewSentryHook(YOUR_DSN, []logrus.Level{ + logrus.PanicLevel, + logrus.FatalLevel, + logrus.ErrorLevel, + }) + + if err == nil { + log.Hooks.Add(hook) + } +} +``` + +If you wish to initialize a SentryHook with tags, you can use the `NewWithTagsSentryHook` constructor to provide default tags: + +```go +tags := map[string]string{ + "site": "example.com", +} +levels := []logrus.Level{ + logrus.PanicLevel, + logrus.FatalLevel, + logrus.ErrorLevel, +} +hook, err := logrus_sentry.NewWithTagsSentryHook(YOUR_DSN, tags, levels) + +``` + +If you wish to initialize a SentryHook with an already initialized raven client, you can use +the `NewWithClientSentryHook` constructor: + +```go +import ( + "github.com/Sirupsen/logrus" + "github.com/Sirupsen/logrus/hooks/sentry" + "github.com/getsentry/raven-go" +) + +func main() { + log := logrus.New() + + client, err := raven.New(YOUR_DSN) + if err != nil { + log.Fatal(err) + } + + hook, err := logrus_sentry.NewWithClientSentryHook(client, []logrus.Level{ + logrus.PanicLevel, + logrus.FatalLevel, + logrus.ErrorLevel, + }) + + if err == nil { + log.Hooks.Add(hook) + } +} + +hook, err := NewWithClientSentryHook(client, []logrus.Level{ + logrus.ErrorLevel, +}) +``` + +## Special fields + +Some logrus fields have a special meaning in this hook, +these are `server_name`, `logger` and `http_request`. +When logs are sent to sentry these fields are treated differently. +- `server_name` (also known as hostname) is the name of the server which +is logging the event (hostname.example.com) +- `logger` is the part of the application which is logging the event. +In go this usually means setting it to the name of the package. +- `http_request` is the in-coming request(*http.Request). The detailed request data are sent to Sentry. + +## Timeout + +`Timeout` is the time the sentry hook will wait for a response +from the sentry server. + +If this time elapses with no response from +the server an error will be returned. + +If `Timeout` is set to 0 the SentryHook will not wait for a reply +and will assume a correct delivery. + +The SentryHook has a default timeout of `100 milliseconds` when created +with a call to `NewSentryHook`. This can be changed by assigning a value to the `Timeout` field: + +```go +hook, _ := logrus_sentry.NewSentryHook(...) +hook.Timeout = 20*time.Second +``` diff --git a/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/hooks/sentry/sentry.go b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/hooks/sentry/sentry.go new file mode 100644 index 0000000..cf88098 --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/hooks/sentry/sentry.go @@ -0,0 +1,137 @@ +package logrus_sentry + +import ( + "fmt" + "net/http" + "time" + + "github.com/Sirupsen/logrus" + "github.com/getsentry/raven-go" +) + +var ( + severityMap = map[logrus.Level]raven.Severity{ + logrus.DebugLevel: raven.DEBUG, + logrus.InfoLevel: raven.INFO, + logrus.WarnLevel: raven.WARNING, + logrus.ErrorLevel: raven.ERROR, + logrus.FatalLevel: raven.FATAL, + logrus.PanicLevel: raven.FATAL, + } +) + +func getAndDel(d logrus.Fields, key string) (string, bool) { + var ( + ok bool + v interface{} + val string + ) + if v, ok = d[key]; !ok { + return "", false + } + + if val, ok = v.(string); !ok { + return "", false + } + delete(d, key) + return val, true +} + +func getAndDelRequest(d logrus.Fields, key string) (*http.Request, bool) { + var ( + ok bool + v interface{} + req *http.Request + ) + if v, ok = d[key]; !ok { + return nil, false + } + if req, ok = v.(*http.Request); !ok || req == nil { + return nil, false + } + delete(d, key) + return req, true +} + +// SentryHook delivers logs to a sentry server. +type SentryHook struct { + // Timeout sets the time to wait for a delivery error from the sentry server. + // If this is set to zero the server will not wait for any response and will + // consider the message correctly sent + Timeout time.Duration + + client *raven.Client + levels []logrus.Level +} + +// NewSentryHook creates a hook to be added to an instance of logger +// and initializes the raven client. +// This method sets the timeout to 100 milliseconds. +func NewSentryHook(DSN string, levels []logrus.Level) (*SentryHook, error) { + client, err := raven.New(DSN) + if err != nil { + return nil, err + } + return &SentryHook{100 * time.Millisecond, client, levels}, nil +} + +// NewWithTagsSentryHook creates a hook with tags to be added to an instance +// of logger and initializes the raven client. This method sets the timeout to +// 100 milliseconds. +func NewWithTagsSentryHook(DSN string, tags map[string]string, levels []logrus.Level) (*SentryHook, error) { + client, err := raven.NewWithTags(DSN, tags) + if err != nil { + return nil, err + } + return &SentryHook{100 * time.Millisecond, client, levels}, nil +} + +// NewWithClientSentryHook creates a hook using an initialized raven client. +// This method sets the timeout to 100 milliseconds. +func NewWithClientSentryHook(client *raven.Client, levels []logrus.Level) (*SentryHook, error) { + return &SentryHook{100 * time.Millisecond, client, levels}, nil +} + +// Called when an event should be sent to sentry +// Special fields that sentry uses to give more information to the server +// are extracted from entry.Data (if they are found) +// These fields are: logger, server_name and http_request +func (hook *SentryHook) Fire(entry *logrus.Entry) error { + packet := &raven.Packet{ + Message: entry.Message, + Timestamp: raven.Timestamp(entry.Time), + Level: severityMap[entry.Level], + Platform: "go", + } + + d := entry.Data + + if logger, ok := getAndDel(d, "logger"); ok { + packet.Logger = logger + } + if serverName, ok := getAndDel(d, "server_name"); ok { + packet.ServerName = serverName + } + if req, ok := getAndDelRequest(d, "http_request"); ok { + packet.Interfaces = append(packet.Interfaces, raven.NewHttp(req)) + } + packet.Extra = map[string]interface{}(d) + + _, errCh := hook.client.Capture(packet, nil) + timeout := hook.Timeout + if timeout != 0 { + timeoutCh := time.After(timeout) + select { + case err := <-errCh: + return err + case <-timeoutCh: + return fmt.Errorf("no response from sentry server in %s", timeout) + } + } + return nil +} + +// Levels returns the available logging levels. +func (hook *SentryHook) Levels() []logrus.Level { + return hook.levels +} diff --git a/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/hooks/sentry/sentry_test.go b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/hooks/sentry/sentry_test.go new file mode 100644 index 0000000..4a97bc6 --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/hooks/sentry/sentry_test.go @@ -0,0 +1,154 @@ +package logrus_sentry + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "net/http/httptest" + "reflect" + "strings" + "testing" + + "github.com/Sirupsen/logrus" + "github.com/getsentry/raven-go" +) + +const ( + message = "error message" + server_name = "testserver.internal" + logger_name = "test.logger" +) + +func getTestLogger() *logrus.Logger { + l := logrus.New() + l.Out = ioutil.Discard + return l +} + +func WithTestDSN(t *testing.T, tf func(string, <-chan *raven.Packet)) { + pch := make(chan *raven.Packet, 1) + s := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { + defer req.Body.Close() + d := json.NewDecoder(req.Body) + p := &raven.Packet{} + err := d.Decode(p) + if err != nil { + t.Fatal(err.Error()) + } + + pch <- p + })) + defer s.Close() + + fragments := strings.SplitN(s.URL, "://", 2) + dsn := fmt.Sprintf( + "%s://public:secret@%s/sentry/project-id", + fragments[0], + fragments[1], + ) + tf(dsn, pch) +} + +func TestSpecialFields(t *testing.T) { + WithTestDSN(t, func(dsn string, pch <-chan *raven.Packet) { + logger := getTestLogger() + + hook, err := NewSentryHook(dsn, []logrus.Level{ + logrus.ErrorLevel, + }) + + if err != nil { + t.Fatal(err.Error()) + } + logger.Hooks.Add(hook) + + req, _ := http.NewRequest("GET", "url", nil) + logger.WithFields(logrus.Fields{ + "server_name": server_name, + "logger": logger_name, + "http_request": req, + }).Error(message) + + packet := <-pch + if packet.Logger != logger_name { + t.Errorf("logger should have been %s, was %s", logger_name, packet.Logger) + } + + if packet.ServerName != server_name { + t.Errorf("server_name should have been %s, was %s", server_name, packet.ServerName) + } + }) +} + +func TestSentryHandler(t *testing.T) { + WithTestDSN(t, func(dsn string, pch <-chan *raven.Packet) { + logger := getTestLogger() + hook, err := NewSentryHook(dsn, []logrus.Level{ + logrus.ErrorLevel, + }) + if err != nil { + t.Fatal(err.Error()) + } + logger.Hooks.Add(hook) + + logger.Error(message) + packet := <-pch + if packet.Message != message { + t.Errorf("message should have been %s, was %s", message, packet.Message) + } + }) +} + +func TestSentryWithClient(t *testing.T) { + WithTestDSN(t, func(dsn string, pch <-chan *raven.Packet) { + logger := getTestLogger() + + client, _ := raven.New(dsn) + + hook, err := NewWithClientSentryHook(client, []logrus.Level{ + logrus.ErrorLevel, + }) + if err != nil { + t.Fatal(err.Error()) + } + logger.Hooks.Add(hook) + + logger.Error(message) + packet := <-pch + if packet.Message != message { + t.Errorf("message should have been %s, was %s", message, packet.Message) + } + }) +} + +func TestSentryTags(t *testing.T) { + WithTestDSN(t, func(dsn string, pch <-chan *raven.Packet) { + logger := getTestLogger() + tags := map[string]string{ + "site": "test", + } + levels := []logrus.Level{ + logrus.ErrorLevel, + } + + hook, err := NewWithTagsSentryHook(dsn, tags, levels) + if err != nil { + t.Fatal(err.Error()) + } + + logger.Hooks.Add(hook) + + logger.Error(message) + packet := <-pch + expected := raven.Tags{ + raven.Tag{ + Key: "site", + Value: "test", + }, + } + if !reflect.DeepEqual(packet.Tags, expected) { + t.Errorf("message should have been %s, was %s", message, packet.Message) + } + }) +} diff --git a/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/hooks/syslog/README.md b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/hooks/syslog/README.md new file mode 100644 index 0000000..4dbb8e7 --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/hooks/syslog/README.md @@ -0,0 +1,20 @@ +# Syslog Hooks for Logrus :walrus: + +## Usage + +```go +import ( + "log/syslog" + "github.com/Sirupsen/logrus" + logrus_syslog "github.com/Sirupsen/logrus/hooks/syslog" +) + +func main() { + log := logrus.New() + hook, err := logrus_syslog.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "") + + if err == nil { + log.Hooks.Add(hook) + } +} +``` diff --git a/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/hooks/syslog/syslog.go b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/hooks/syslog/syslog.go new file mode 100644 index 0000000..b6fa374 --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/hooks/syslog/syslog.go @@ -0,0 +1,59 @@ +package logrus_syslog + +import ( + "fmt" + "github.com/Sirupsen/logrus" + "log/syslog" + "os" +) + +// SyslogHook to send logs via syslog. +type SyslogHook struct { + Writer *syslog.Writer + SyslogNetwork string + SyslogRaddr string +} + +// Creates a hook to be added to an instance of logger. This is called with +// `hook, err := NewSyslogHook("udp", "localhost:514", syslog.LOG_DEBUG, "")` +// `if err == nil { log.Hooks.Add(hook) }` +func NewSyslogHook(network, raddr string, priority syslog.Priority, tag string) (*SyslogHook, error) { + w, err := syslog.Dial(network, raddr, priority, tag) + return &SyslogHook{w, network, raddr}, err +} + +func (hook *SyslogHook) Fire(entry *logrus.Entry) error { + line, err := entry.String() + if err != nil { + fmt.Fprintf(os.Stderr, "Unable to read entry, %v", err) + return err + } + + switch entry.Level { + case logrus.PanicLevel: + return hook.Writer.Crit(line) + case logrus.FatalLevel: + return hook.Writer.Crit(line) + case logrus.ErrorLevel: + return hook.Writer.Err(line) + case logrus.WarnLevel: + return hook.Writer.Warning(line) + case logrus.InfoLevel: + return hook.Writer.Info(line) + case logrus.DebugLevel: + return hook.Writer.Debug(line) + default: + return nil + } +} + +func (hook *SyslogHook) Levels() []logrus.Level { + return []logrus.Level{ + logrus.PanicLevel, + logrus.FatalLevel, + logrus.ErrorLevel, + logrus.WarnLevel, + logrus.InfoLevel, + logrus.DebugLevel, + } +} diff --git a/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/hooks/syslog/syslog_test.go b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/hooks/syslog/syslog_test.go new file mode 100644 index 0000000..42762dc --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/hooks/syslog/syslog_test.go @@ -0,0 +1,26 @@ +package logrus_syslog + +import ( + "github.com/Sirupsen/logrus" + "log/syslog" + "testing" +) + +func TestLocalhostAddAndPrint(t *testing.T) { + log := logrus.New() + hook, err := NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "") + + if err != nil { + t.Errorf("Unable to connect to local syslog.") + } + + log.Hooks.Add(hook) + + for _, level := range hook.Levels() { + if len(log.Hooks[level]) != 1 { + t.Errorf("SyslogHook was not added. The length of log.Hooks[%v]: %v", level, len(log.Hooks[level])) + } + } + + log.Info("Congratulations!") +} diff --git a/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/json_formatter.go b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/json_formatter.go new file mode 100644 index 0000000..2ad6dc5 --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/json_formatter.go @@ -0,0 +1,41 @@ +package logrus + +import ( + "encoding/json" + "fmt" +) + +type JSONFormatter struct { + // TimestampFormat sets the format used for marshaling timestamps. + TimestampFormat string +} + +func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) { + data := make(Fields, len(entry.Data)+3) + for k, v := range entry.Data { + switch v := v.(type) { + case error: + // Otherwise errors are ignored by `encoding/json` + // https://github.com/Sirupsen/logrus/issues/137 + data[k] = v.Error() + default: + data[k] = v + } + } + prefixFieldClashes(data) + + timestampFormat := f.TimestampFormat + if timestampFormat == "" { + timestampFormat = DefaultTimestampFormat + } + + data["time"] = entry.Time.Format(timestampFormat) + data["msg"] = entry.Message + data["level"] = entry.Level.String() + + serialized, err := json.Marshal(data) + if err != nil { + return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err) + } + return append(serialized, '\n'), nil +} diff --git a/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/json_formatter_test.go b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/json_formatter_test.go new file mode 100644 index 0000000..1d70873 --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/json_formatter_test.go @@ -0,0 +1,120 @@ +package logrus + +import ( + "encoding/json" + "errors" + + "testing" +) + +func TestErrorNotLost(t *testing.T) { + formatter := &JSONFormatter{} + + b, err := formatter.Format(WithField("error", errors.New("wild walrus"))) + if err != nil { + t.Fatal("Unable to format entry: ", err) + } + + entry := make(map[string]interface{}) + err = json.Unmarshal(b, &entry) + if err != nil { + t.Fatal("Unable to unmarshal formatted entry: ", err) + } + + if entry["error"] != "wild walrus" { + t.Fatal("Error field not set") + } +} + +func TestErrorNotLostOnFieldNotNamedError(t *testing.T) { + formatter := &JSONFormatter{} + + b, err := formatter.Format(WithField("omg", errors.New("wild walrus"))) + if err != nil { + t.Fatal("Unable to format entry: ", err) + } + + entry := make(map[string]interface{}) + err = json.Unmarshal(b, &entry) + if err != nil { + t.Fatal("Unable to unmarshal formatted entry: ", err) + } + + if entry["omg"] != "wild walrus" { + t.Fatal("Error field not set") + } +} + +func TestFieldClashWithTime(t *testing.T) { + formatter := &JSONFormatter{} + + b, err := formatter.Format(WithField("time", "right now!")) + if err != nil { + t.Fatal("Unable to format entry: ", err) + } + + entry := make(map[string]interface{}) + err = json.Unmarshal(b, &entry) + if err != nil { + t.Fatal("Unable to unmarshal formatted entry: ", err) + } + + if entry["fields.time"] != "right now!" { + t.Fatal("fields.time not set to original time field") + } + + if entry["time"] != "0001-01-01T00:00:00Z" { + t.Fatal("time field not set to current time, was: ", entry["time"]) + } +} + +func TestFieldClashWithMsg(t *testing.T) { + formatter := &JSONFormatter{} + + b, err := formatter.Format(WithField("msg", "something")) + if err != nil { + t.Fatal("Unable to format entry: ", err) + } + + entry := make(map[string]interface{}) + err = json.Unmarshal(b, &entry) + if err != nil { + t.Fatal("Unable to unmarshal formatted entry: ", err) + } + + if entry["fields.msg"] != "something" { + t.Fatal("fields.msg not set to original msg field") + } +} + +func TestFieldClashWithLevel(t *testing.T) { + formatter := &JSONFormatter{} + + b, err := formatter.Format(WithField("level", "something")) + if err != nil { + t.Fatal("Unable to format entry: ", err) + } + + entry := make(map[string]interface{}) + err = json.Unmarshal(b, &entry) + if err != nil { + t.Fatal("Unable to unmarshal formatted entry: ", err) + } + + if entry["fields.level"] != "something" { + t.Fatal("fields.level not set to original level field") + } +} + +func TestJSONEntryEndsWithNewline(t *testing.T) { + formatter := &JSONFormatter{} + + b, err := formatter.Format(WithField("level", "something")) + if err != nil { + t.Fatal("Unable to format entry: ", err) + } + + if b[len(b)-1] != '\n' { + t.Fatal("Expected JSON log entry to end with a newline") + } +} diff --git a/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/logger.go b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/logger.go new file mode 100644 index 0000000..fd9804c --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/logger.go @@ -0,0 +1,206 @@ +package logrus + +import ( + "io" + "os" + "sync" +) + +type Logger struct { + // The logs are `io.Copy`'d to this in a mutex. It's common to set this to a + // file, or leave it default which is `os.Stderr`. You can also set this to + // something more adventorous, such as logging to Kafka. + Out io.Writer + // Hooks for the logger instance. These allow firing events based on logging + // levels and log entries. For example, to send errors to an error tracking + // service, log to StatsD or dump the core on fatal errors. + Hooks LevelHooks + // All log entries pass through the formatter before logged to Out. The + // included formatters are `TextFormatter` and `JSONFormatter` for which + // TextFormatter is the default. In development (when a TTY is attached) it + // logs with colors, but to a file it wouldn't. You can easily implement your + // own that implements the `Formatter` interface, see the `README` or included + // formatters for examples. + Formatter Formatter + // The logging level the logger should log at. This is typically (and defaults + // to) `logrus.Info`, which allows Info(), Warn(), Error() and Fatal() to be + // logged. `logrus.Debug` is useful in + Level Level + // Used to sync writing to the log. + mu sync.Mutex +} + +// Creates a new logger. Configuration should be set by changing `Formatter`, +// `Out` and `Hooks` directly on the default logger instance. You can also just +// instantiate your own: +// +// var log = &Logger{ +// Out: os.Stderr, +// Formatter: new(JSONFormatter), +// Hooks: make(LevelHooks), +// Level: logrus.DebugLevel, +// } +// +// It's recommended to make this a global instance called `log`. +func New() *Logger { + return &Logger{ + Out: os.Stderr, + Formatter: new(TextFormatter), + Hooks: make(LevelHooks), + Level: InfoLevel, + } +} + +// Adds a field to the log entry, note that you it doesn't log until you call +// Debug, Print, Info, Warn, Fatal or Panic. It only creates a log entry. +// If you want multiple fields, use `WithFields`. +func (logger *Logger) WithField(key string, value interface{}) *Entry { + return NewEntry(logger).WithField(key, value) +} + +// Adds a struct of fields to the log entry. All it does is call `WithField` for +// each `Field`. +func (logger *Logger) WithFields(fields Fields) *Entry { + return NewEntry(logger).WithFields(fields) +} + +func (logger *Logger) Debugf(format string, args ...interface{}) { + if logger.Level >= DebugLevel { + NewEntry(logger).Debugf(format, args...) + } +} + +func (logger *Logger) Infof(format string, args ...interface{}) { + if logger.Level >= InfoLevel { + NewEntry(logger).Infof(format, args...) + } +} + +func (logger *Logger) Printf(format string, args ...interface{}) { + NewEntry(logger).Printf(format, args...) +} + +func (logger *Logger) Warnf(format string, args ...interface{}) { + if logger.Level >= WarnLevel { + NewEntry(logger).Warnf(format, args...) + } +} + +func (logger *Logger) Warningf(format string, args ...interface{}) { + if logger.Level >= WarnLevel { + NewEntry(logger).Warnf(format, args...) + } +} + +func (logger *Logger) Errorf(format string, args ...interface{}) { + if logger.Level >= ErrorLevel { + NewEntry(logger).Errorf(format, args...) + } +} + +func (logger *Logger) Fatalf(format string, args ...interface{}) { + if logger.Level >= FatalLevel { + NewEntry(logger).Fatalf(format, args...) + } + os.Exit(1) +} + +func (logger *Logger) Panicf(format string, args ...interface{}) { + if logger.Level >= PanicLevel { + NewEntry(logger).Panicf(format, args...) + } +} + +func (logger *Logger) Debug(args ...interface{}) { + if logger.Level >= DebugLevel { + NewEntry(logger).Debug(args...) + } +} + +func (logger *Logger) Info(args ...interface{}) { + if logger.Level >= InfoLevel { + NewEntry(logger).Info(args...) + } +} + +func (logger *Logger) Print(args ...interface{}) { + NewEntry(logger).Info(args...) +} + +func (logger *Logger) Warn(args ...interface{}) { + if logger.Level >= WarnLevel { + NewEntry(logger).Warn(args...) + } +} + +func (logger *Logger) Warning(args ...interface{}) { + if logger.Level >= WarnLevel { + NewEntry(logger).Warn(args...) + } +} + +func (logger *Logger) Error(args ...interface{}) { + if logger.Level >= ErrorLevel { + NewEntry(logger).Error(args...) + } +} + +func (logger *Logger) Fatal(args ...interface{}) { + if logger.Level >= FatalLevel { + NewEntry(logger).Fatal(args...) + } + os.Exit(1) +} + +func (logger *Logger) Panic(args ...interface{}) { + if logger.Level >= PanicLevel { + NewEntry(logger).Panic(args...) + } +} + +func (logger *Logger) Debugln(args ...interface{}) { + if logger.Level >= DebugLevel { + NewEntry(logger).Debugln(args...) + } +} + +func (logger *Logger) Infoln(args ...interface{}) { + if logger.Level >= InfoLevel { + NewEntry(logger).Infoln(args...) + } +} + +func (logger *Logger) Println(args ...interface{}) { + NewEntry(logger).Println(args...) +} + +func (logger *Logger) Warnln(args ...interface{}) { + if logger.Level >= WarnLevel { + NewEntry(logger).Warnln(args...) + } +} + +func (logger *Logger) Warningln(args ...interface{}) { + if logger.Level >= WarnLevel { + NewEntry(logger).Warnln(args...) + } +} + +func (logger *Logger) Errorln(args ...interface{}) { + if logger.Level >= ErrorLevel { + NewEntry(logger).Errorln(args...) + } +} + +func (logger *Logger) Fatalln(args ...interface{}) { + if logger.Level >= FatalLevel { + NewEntry(logger).Fatalln(args...) + } + os.Exit(1) +} + +func (logger *Logger) Panicln(args ...interface{}) { + if logger.Level >= PanicLevel { + NewEntry(logger).Panicln(args...) + } +} diff --git a/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/logrus.go b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/logrus.go new file mode 100644 index 0000000..43ee12e --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/logrus.go @@ -0,0 +1,94 @@ +package logrus + +import ( + "fmt" + "log" +) + +// Fields type, used to pass to `WithFields`. +type Fields map[string]interface{} + +// Level type +type Level uint8 + +// Convert the Level to a string. E.g. PanicLevel becomes "panic". +func (level Level) String() string { + switch level { + case DebugLevel: + return "debug" + case InfoLevel: + return "info" + case WarnLevel: + return "warning" + case ErrorLevel: + return "error" + case FatalLevel: + return "fatal" + case PanicLevel: + return "panic" + } + + return "unknown" +} + +// ParseLevel takes a string level and returns the Logrus log level constant. +func ParseLevel(lvl string) (Level, error) { + switch lvl { + case "panic": + return PanicLevel, nil + case "fatal": + return FatalLevel, nil + case "error": + return ErrorLevel, nil + case "warn", "warning": + return WarnLevel, nil + case "info": + return InfoLevel, nil + case "debug": + return DebugLevel, nil + } + + var l Level + return l, fmt.Errorf("not a valid logrus Level: %q", lvl) +} + +// These are the different logging levels. You can set the logging level to log +// on your instance of logger, obtained with `logrus.New()`. +const ( + // PanicLevel level, highest level of severity. Logs and then calls panic with the + // message passed to Debug, Info, ... + PanicLevel Level = iota + // FatalLevel level. Logs and then calls `os.Exit(1)`. It will exit even if the + // logging level is set to Panic. + FatalLevel + // ErrorLevel level. Logs. Used for errors that should definitely be noted. + // Commonly used for hooks to send errors to an error tracking service. + ErrorLevel + // WarnLevel level. Non-critical entries that deserve eyes. + WarnLevel + // InfoLevel level. General operational entries about what's going on inside the + // application. + InfoLevel + // DebugLevel level. Usually only enabled when debugging. Very verbose logging. + DebugLevel +) + +// Won't compile if StdLogger can't be realized by a log.Logger +var _ StdLogger = &log.Logger{} + +// StdLogger is what your logrus-enabled library should take, that way +// it'll accept a stdlib logger and a logrus logger. There's no standard +// interface, this is the closest we get, unfortunately. +type StdLogger interface { + Print(...interface{}) + Printf(string, ...interface{}) + Println(...interface{}) + + Fatal(...interface{}) + Fatalf(string, ...interface{}) + Fatalln(...interface{}) + + Panic(...interface{}) + Panicf(string, ...interface{}) + Panicln(...interface{}) +} diff --git a/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/logrus_test.go b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/logrus_test.go new file mode 100644 index 0000000..efaacea --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/logrus_test.go @@ -0,0 +1,301 @@ +package logrus + +import ( + "bytes" + "encoding/json" + "strconv" + "strings" + "sync" + "testing" + + "github.com/stretchr/testify/assert" +) + +func LogAndAssertJSON(t *testing.T, log func(*Logger), assertions func(fields Fields)) { + var buffer bytes.Buffer + var fields Fields + + logger := New() + logger.Out = &buffer + logger.Formatter = new(JSONFormatter) + + log(logger) + + err := json.Unmarshal(buffer.Bytes(), &fields) + assert.Nil(t, err) + + assertions(fields) +} + +func LogAndAssertText(t *testing.T, log func(*Logger), assertions func(fields map[string]string)) { + var buffer bytes.Buffer + + logger := New() + logger.Out = &buffer + logger.Formatter = &TextFormatter{ + DisableColors: true, + } + + log(logger) + + fields := make(map[string]string) + for _, kv := range strings.Split(buffer.String(), " ") { + if !strings.Contains(kv, "=") { + continue + } + kvArr := strings.Split(kv, "=") + key := strings.TrimSpace(kvArr[0]) + val := kvArr[1] + if kvArr[1][0] == '"' { + var err error + val, err = strconv.Unquote(val) + assert.NoError(t, err) + } + fields[key] = val + } + assertions(fields) +} + +func TestPrint(t *testing.T) { + LogAndAssertJSON(t, func(log *Logger) { + log.Print("test") + }, func(fields Fields) { + assert.Equal(t, fields["msg"], "test") + assert.Equal(t, fields["level"], "info") + }) +} + +func TestInfo(t *testing.T) { + LogAndAssertJSON(t, func(log *Logger) { + log.Info("test") + }, func(fields Fields) { + assert.Equal(t, fields["msg"], "test") + assert.Equal(t, fields["level"], "info") + }) +} + +func TestWarn(t *testing.T) { + LogAndAssertJSON(t, func(log *Logger) { + log.Warn("test") + }, func(fields Fields) { + assert.Equal(t, fields["msg"], "test") + assert.Equal(t, fields["level"], "warning") + }) +} + +func TestInfolnShouldAddSpacesBetweenStrings(t *testing.T) { + LogAndAssertJSON(t, func(log *Logger) { + log.Infoln("test", "test") + }, func(fields Fields) { + assert.Equal(t, fields["msg"], "test test") + }) +} + +func TestInfolnShouldAddSpacesBetweenStringAndNonstring(t *testing.T) { + LogAndAssertJSON(t, func(log *Logger) { + log.Infoln("test", 10) + }, func(fields Fields) { + assert.Equal(t, fields["msg"], "test 10") + }) +} + +func TestInfolnShouldAddSpacesBetweenTwoNonStrings(t *testing.T) { + LogAndAssertJSON(t, func(log *Logger) { + log.Infoln(10, 10) + }, func(fields Fields) { + assert.Equal(t, fields["msg"], "10 10") + }) +} + +func TestInfoShouldAddSpacesBetweenTwoNonStrings(t *testing.T) { + LogAndAssertJSON(t, func(log *Logger) { + log.Infoln(10, 10) + }, func(fields Fields) { + assert.Equal(t, fields["msg"], "10 10") + }) +} + +func TestInfoShouldNotAddSpacesBetweenStringAndNonstring(t *testing.T) { + LogAndAssertJSON(t, func(log *Logger) { + log.Info("test", 10) + }, func(fields Fields) { + assert.Equal(t, fields["msg"], "test10") + }) +} + +func TestInfoShouldNotAddSpacesBetweenStrings(t *testing.T) { + LogAndAssertJSON(t, func(log *Logger) { + log.Info("test", "test") + }, func(fields Fields) { + assert.Equal(t, fields["msg"], "testtest") + }) +} + +func TestWithFieldsShouldAllowAssignments(t *testing.T) { + var buffer bytes.Buffer + var fields Fields + + logger := New() + logger.Out = &buffer + logger.Formatter = new(JSONFormatter) + + localLog := logger.WithFields(Fields{ + "key1": "value1", + }) + + localLog.WithField("key2", "value2").Info("test") + err := json.Unmarshal(buffer.Bytes(), &fields) + assert.Nil(t, err) + + assert.Equal(t, "value2", fields["key2"]) + assert.Equal(t, "value1", fields["key1"]) + + buffer = bytes.Buffer{} + fields = Fields{} + localLog.Info("test") + err = json.Unmarshal(buffer.Bytes(), &fields) + assert.Nil(t, err) + + _, ok := fields["key2"] + assert.Equal(t, false, ok) + assert.Equal(t, "value1", fields["key1"]) +} + +func TestUserSuppliedFieldDoesNotOverwriteDefaults(t *testing.T) { + LogAndAssertJSON(t, func(log *Logger) { + log.WithField("msg", "hello").Info("test") + }, func(fields Fields) { + assert.Equal(t, fields["msg"], "test") + }) +} + +func TestUserSuppliedMsgFieldHasPrefix(t *testing.T) { + LogAndAssertJSON(t, func(log *Logger) { + log.WithField("msg", "hello").Info("test") + }, func(fields Fields) { + assert.Equal(t, fields["msg"], "test") + assert.Equal(t, fields["fields.msg"], "hello") + }) +} + +func TestUserSuppliedTimeFieldHasPrefix(t *testing.T) { + LogAndAssertJSON(t, func(log *Logger) { + log.WithField("time", "hello").Info("test") + }, func(fields Fields) { + assert.Equal(t, fields["fields.time"], "hello") + }) +} + +func TestUserSuppliedLevelFieldHasPrefix(t *testing.T) { + LogAndAssertJSON(t, func(log *Logger) { + log.WithField("level", 1).Info("test") + }, func(fields Fields) { + assert.Equal(t, fields["level"], "info") + assert.Equal(t, fields["fields.level"], 1.0) // JSON has floats only + }) +} + +func TestDefaultFieldsAreNotPrefixed(t *testing.T) { + LogAndAssertText(t, func(log *Logger) { + ll := log.WithField("herp", "derp") + ll.Info("hello") + ll.Info("bye") + }, func(fields map[string]string) { + for _, fieldName := range []string{"fields.level", "fields.time", "fields.msg"} { + if _, ok := fields[fieldName]; ok { + t.Fatalf("should not have prefixed %q: %v", fieldName, fields) + } + } + }) +} + +func TestDoubleLoggingDoesntPrefixPreviousFields(t *testing.T) { + + var buffer bytes.Buffer + var fields Fields + + logger := New() + logger.Out = &buffer + logger.Formatter = new(JSONFormatter) + + llog := logger.WithField("context", "eating raw fish") + + llog.Info("looks delicious") + + err := json.Unmarshal(buffer.Bytes(), &fields) + assert.NoError(t, err, "should have decoded first message") + assert.Equal(t, len(fields), 4, "should only have msg/time/level/context fields") + assert.Equal(t, fields["msg"], "looks delicious") + assert.Equal(t, fields["context"], "eating raw fish") + + buffer.Reset() + + llog.Warn("omg it is!") + + err = json.Unmarshal(buffer.Bytes(), &fields) + assert.NoError(t, err, "should have decoded second message") + assert.Equal(t, len(fields), 4, "should only have msg/time/level/context fields") + assert.Equal(t, fields["msg"], "omg it is!") + assert.Equal(t, fields["context"], "eating raw fish") + assert.Nil(t, fields["fields.msg"], "should not have prefixed previous `msg` entry") + +} + +func TestConvertLevelToString(t *testing.T) { + assert.Equal(t, "debug", DebugLevel.String()) + assert.Equal(t, "info", InfoLevel.String()) + assert.Equal(t, "warning", WarnLevel.String()) + assert.Equal(t, "error", ErrorLevel.String()) + assert.Equal(t, "fatal", FatalLevel.String()) + assert.Equal(t, "panic", PanicLevel.String()) +} + +func TestParseLevel(t *testing.T) { + l, err := ParseLevel("panic") + assert.Nil(t, err) + assert.Equal(t, PanicLevel, l) + + l, err = ParseLevel("fatal") + assert.Nil(t, err) + assert.Equal(t, FatalLevel, l) + + l, err = ParseLevel("error") + assert.Nil(t, err) + assert.Equal(t, ErrorLevel, l) + + l, err = ParseLevel("warn") + assert.Nil(t, err) + assert.Equal(t, WarnLevel, l) + + l, err = ParseLevel("warning") + assert.Nil(t, err) + assert.Equal(t, WarnLevel, l) + + l, err = ParseLevel("info") + assert.Nil(t, err) + assert.Equal(t, InfoLevel, l) + + l, err = ParseLevel("debug") + assert.Nil(t, err) + assert.Equal(t, DebugLevel, l) + + l, err = ParseLevel("invalid") + assert.Equal(t, "not a valid logrus Level: \"invalid\"", err.Error()) +} + +func TestGetSetLevelRace(t *testing.T) { + wg := sync.WaitGroup{} + for i := 0; i < 100; i++ { + wg.Add(1) + go func(i int) { + defer wg.Done() + if i%2 == 0 { + SetLevel(InfoLevel) + } else { + GetLevel() + } + }(i) + + } + wg.Wait() +} diff --git a/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/terminal_bsd.go b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/terminal_bsd.go new file mode 100644 index 0000000..71f8d67 --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/terminal_bsd.go @@ -0,0 +1,9 @@ +// +build darwin freebsd openbsd netbsd dragonfly + +package logrus + +import "syscall" + +const ioctlReadTermios = syscall.TIOCGETA + +type Termios syscall.Termios diff --git a/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/terminal_linux.go b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/terminal_linux.go new file mode 100644 index 0000000..a2c0b40 --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/terminal_linux.go @@ -0,0 +1,12 @@ +// Based on ssh/terminal: +// 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 logrus + +import "syscall" + +const ioctlReadTermios = syscall.TCGETS + +type Termios syscall.Termios diff --git a/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/terminal_notwindows.go b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/terminal_notwindows.go new file mode 100644 index 0000000..4bb5376 --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/terminal_notwindows.go @@ -0,0 +1,21 @@ +// Based on ssh/terminal: +// 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 linux darwin freebsd openbsd netbsd dragonfly + +package logrus + +import ( + "syscall" + "unsafe" +) + +// IsTerminal returns true if the given file descriptor is a terminal. +func IsTerminal() bool { + fd := syscall.Stdout + var termios Termios + _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0) + return err == 0 +} diff --git a/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/terminal_windows.go b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/terminal_windows.go new file mode 100644 index 0000000..2e09f6f --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/terminal_windows.go @@ -0,0 +1,27 @@ +// Based on ssh/terminal: +// 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 windows + +package logrus + +import ( + "syscall" + "unsafe" +) + +var kernel32 = syscall.NewLazyDLL("kernel32.dll") + +var ( + procGetConsoleMode = kernel32.NewProc("GetConsoleMode") +) + +// IsTerminal returns true if the given file descriptor is a terminal. +func IsTerminal() bool { + fd := syscall.Stdout + var st uint32 + r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0) + return r != 0 && e == 0 +} diff --git a/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/text_formatter.go b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/text_formatter.go new file mode 100644 index 0000000..17cc298 --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/text_formatter.go @@ -0,0 +1,159 @@ +package logrus + +import ( + "bytes" + "fmt" + "runtime" + "sort" + "strings" + "time" +) + +const ( + nocolor = 0 + red = 31 + green = 32 + yellow = 33 + blue = 34 + gray = 37 +) + +var ( + baseTimestamp time.Time + isTerminal bool +) + +func init() { + baseTimestamp = time.Now() + isTerminal = IsTerminal() +} + +func miniTS() int { + return int(time.Since(baseTimestamp) / time.Second) +} + +type TextFormatter struct { + // Set to true to bypass checking for a TTY before outputting colors. + ForceColors bool + + // Force disabling colors. + DisableColors bool + + // Disable timestamp logging. useful when output is redirected to logging + // system that already adds timestamps. + DisableTimestamp bool + + // Enable logging the full timestamp when a TTY is attached instead of just + // the time passed since beginning of execution. + FullTimestamp bool + + // TimestampFormat to use for display when a full timestamp is printed + TimestampFormat string + + // The fields are sorted by default for a consistent output. For applications + // that log extremely frequently and don't use the JSON formatter this may not + // be desired. + DisableSorting bool +} + +func (f *TextFormatter) Format(entry *Entry) ([]byte, error) { + var keys []string = make([]string, 0, len(entry.Data)) + for k := range entry.Data { + keys = append(keys, k) + } + + if !f.DisableSorting { + sort.Strings(keys) + } + + b := &bytes.Buffer{} + + prefixFieldClashes(entry.Data) + + isColorTerminal := isTerminal && (runtime.GOOS != "windows") + isColored := (f.ForceColors || isColorTerminal) && !f.DisableColors + + timestampFormat := f.TimestampFormat + if timestampFormat == "" { + timestampFormat = DefaultTimestampFormat + } + if isColored { + f.printColored(b, entry, keys, timestampFormat) + } else { + if !f.DisableTimestamp { + f.appendKeyValue(b, "time", entry.Time.Format(timestampFormat)) + } + f.appendKeyValue(b, "level", entry.Level.String()) + f.appendKeyValue(b, "msg", entry.Message) + for _, key := range keys { + f.appendKeyValue(b, key, entry.Data[key]) + } + } + + b.WriteByte('\n') + return b.Bytes(), nil +} + +func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []string, timestampFormat string) { + var levelColor int + switch entry.Level { + case DebugLevel: + levelColor = gray + case WarnLevel: + levelColor = yellow + case ErrorLevel, FatalLevel, PanicLevel: + levelColor = red + default: + levelColor = blue + } + + levelText := strings.ToUpper(entry.Level.String())[0:4] + + if !f.FullTimestamp { + fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d] %-44s ", levelColor, levelText, miniTS(), entry.Message) + } else { + fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%s] %-44s ", levelColor, levelText, entry.Time.Format(timestampFormat), entry.Message) + } + for _, k := range keys { + v := entry.Data[k] + fmt.Fprintf(b, " \x1b[%dm%s\x1b[0m=%+v", levelColor, k, v) + } +} + +func needsQuoting(text string) bool { + for _, ch := range text { + if !((ch >= 'a' && ch <= 'z') || + (ch >= 'A' && ch <= 'Z') || + (ch >= '0' && ch <= '9') || + ch == '-' || ch == '.') { + return false + } + } + return true +} + +func (f *TextFormatter) appendKeyValue(b *bytes.Buffer, key string, value interface{}) { + + b.WriteString(key) + b.WriteByte('=') + + switch value := value.(type) { + case string: + if needsQuoting(value) { + b.WriteString(value) + } else { + fmt.Fprintf(b, "%q", value) + } + case error: + errmsg := value.Error() + if needsQuoting(errmsg) { + b.WriteString(errmsg) + } else { + fmt.Fprintf(b, "%q", value) + } + default: + fmt.Fprint(b, value) + } + + b.WriteByte(' ') +} diff --git a/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/text_formatter_test.go b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/text_formatter_test.go new file mode 100644 index 0000000..e25a44f --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/text_formatter_test.go @@ -0,0 +1,61 @@ +package logrus + +import ( + "bytes" + "errors" + "testing" + "time" +) + +func TestQuoting(t *testing.T) { + tf := &TextFormatter{DisableColors: true} + + checkQuoting := func(q bool, value interface{}) { + b, _ := tf.Format(WithField("test", value)) + idx := bytes.Index(b, ([]byte)("test=")) + cont := bytes.Contains(b[idx+5:], []byte{'"'}) + if cont != q { + if q { + t.Errorf("quoting expected for: %#v", value) + } else { + t.Errorf("quoting not expected for: %#v", value) + } + } + } + + checkQuoting(false, "abcd") + checkQuoting(false, "v1.0") + checkQuoting(false, "1234567890") + checkQuoting(true, "/foobar") + checkQuoting(true, "x y") + checkQuoting(true, "x,y") + checkQuoting(false, errors.New("invalid")) + checkQuoting(true, errors.New("invalid argument")) +} + +func TestTimestampFormat(t *testing.T) { + checkTimeStr := func(format string) { + customFormatter := &TextFormatter{DisableColors: true, TimestampFormat: format} + customStr, _ := customFormatter.Format(WithField("test", "test")) + timeStart := bytes.Index(customStr, ([]byte)("time=")) + timeEnd := bytes.Index(customStr, ([]byte)("level=")) + timeStr := customStr[timeStart+5 : timeEnd-1] + if timeStr[0] == '"' && timeStr[len(timeStr)-1] == '"' { + timeStr = timeStr[1 : len(timeStr)-1] + } + if format == "" { + format = time.RFC3339 + } + _, e := time.Parse(format, (string)(timeStr)) + if e != nil { + t.Errorf("time string \"%s\" did not match provided time format \"%s\": %s", timeStr, format, e) + } + } + + checkTimeStr("2006-01-02T15:04:05.000000000Z07:00") + checkTimeStr("Mon Jan _2 15:04:05 2006") + checkTimeStr("") +} + +// TODO add tests for sorting etc., this requires a parser for the text +// formatter output. diff --git a/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/writer.go b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/writer.go new file mode 100644 index 0000000..1e30b1c --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/Sirupsen/logrus/writer.go @@ -0,0 +1,31 @@ +package logrus + +import ( + "bufio" + "io" + "runtime" +) + +func (logger *Logger) Writer() *io.PipeWriter { + reader, writer := io.Pipe() + + go logger.writerScanner(reader) + runtime.SetFinalizer(writer, writerFinalizer) + + return writer +} + +func (logger *Logger) writerScanner(reader *io.PipeReader) { + scanner := bufio.NewScanner(reader) + for scanner.Scan() { + logger.Print(scanner.Text()) + } + if err := scanner.Err(); err != nil { + logger.Errorf("Error while reading from Writer: %s", err) + } + reader.Close() +} + +func writerFinalizer(writer *io.PipeWriter) { + writer.Close() +} diff --git a/contrib/backends/nntpchand/src/vendor/github.com/dchest/blake256/README.markdown b/contrib/backends/nntpchand/src/vendor/github.com/dchest/blake256/README.markdown new file mode 100644 index 0000000..98426c2 --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/dchest/blake256/README.markdown @@ -0,0 +1,56 @@ +Package blake256 +===================== + + import "github.com/dchest/blake256" + +Package blake256 implements BLAKE-256 and BLAKE-224 hash functions (SHA-3 +candidate). + +Public domain. + + +Constants +--------- + +``` go +const BlockSize = 64 +``` +The block size of the hash algorithm in bytes. + +``` go +const Size = 32 +``` +The size of BLAKE-256 hash in bytes. + +``` go +const Size224 = 28 +``` +The size of BLAKE-224 hash in bytes. + + +Functions +--------- + +### func New + + func New() hash.Hash + +New returns a new hash.Hash computing the BLAKE-256 checksum. + +### func New224 + + func New224() hash.Hash + +New224 returns a new hash.Hash computing the BLAKE-224 checksum. + +### func New224Salt + + func New224Salt(salt []byte) hash.Hash + +New224Salt is like New224 but initializes salt with the given 16-byte slice. + +### func NewSalt + + func NewSalt(salt []byte) hash.Hash + +NewSalt is like New but initializes salt with the given 16-byte slice. diff --git a/contrib/backends/nntpchand/src/vendor/github.com/dchest/blake256/blake256.go b/contrib/backends/nntpchand/src/vendor/github.com/dchest/blake256/blake256.go new file mode 100644 index 0000000..148ec9e --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/dchest/blake256/blake256.go @@ -0,0 +1,194 @@ +// Written in 2011-2012 by Dmitry Chestnykh. +// +// To the extent possible under law, the author have dedicated all copyright +// and related and neighboring rights to this software to the public domain +// worldwide. This software is distributed without any warranty. +// http://creativecommons.org/publicdomain/zero/1.0/ + +// Package blake256 implements BLAKE-256 and BLAKE-224 hash functions (SHA-3 +// candidate). +package blake256 + +import "hash" + +// The block size of the hash algorithm in bytes. +const BlockSize = 64 + +// The size of BLAKE-256 hash in bytes. +const Size = 32 + +// The size of BLAKE-224 hash in bytes. +const Size224 = 28 + +type digest struct { + hashSize int // hash output size in bits (224 or 256) + h [8]uint32 // current chain value + s [4]uint32 // salt (zero by default) + t uint64 // message bits counter + nullt bool // special case for finalization: skip counter + x [BlockSize]byte // buffer for data not yet compressed + nx int // number of bytes in buffer +} + +var ( + // Initialization values. + iv256 = [8]uint32{ + 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, + 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19} + + iv224 = [8]uint32{ + 0xC1059ED8, 0x367CD507, 0x3070DD17, 0xF70E5939, + 0xFFC00B31, 0x68581511, 0x64F98FA7, 0xBEFA4FA4} + + pad = [64]byte{0x80} +) + +// Reset resets the state of digest. It leaves salt intact. +func (d *digest) Reset() { + if d.hashSize == 224 { + d.h = iv224 + } else { + d.h = iv256 + } + d.t = 0 + d.nx = 0 + d.nullt = false +} + +func (d *digest) Size() int { return d.hashSize >> 3 } + +func (d *digest) BlockSize() int { return BlockSize } + +func (d *digest) Write(p []byte) (nn int, err error) { + nn = len(p) + if d.nx > 0 { + n := len(p) + if n > BlockSize-d.nx { + n = BlockSize - d.nx + } + d.nx += copy(d.x[d.nx:], p) + if d.nx == BlockSize { + block(d, d.x[:]) + d.nx = 0 + } + p = p[n:] + } + if len(p) >= BlockSize { + n := len(p) &^ (BlockSize - 1) + block(d, p[:n]) + p = p[n:] + } + if len(p) > 0 { + d.nx = copy(d.x[:], p) + } + return +} + +// Sum returns the calculated checksum. +func (d0 *digest) Sum(in []byte) []byte { + // Make a copy of d0 so that caller can keep writing and summing. + d := *d0 + + nx := uint64(d.nx) + l := d.t + nx<<3 + len := make([]byte, 8) + len[0] = byte(l >> 56) + len[1] = byte(l >> 48) + len[2] = byte(l >> 40) + len[3] = byte(l >> 32) + len[4] = byte(l >> 24) + len[5] = byte(l >> 16) + len[6] = byte(l >> 8) + len[7] = byte(l) + + if nx == 55 { + // One padding byte. + d.t -= 8 + if d.hashSize == 224 { + d.Write([]byte{0x80}) + } else { + d.Write([]byte{0x81}) + } + } else { + if nx < 55 { + // Enough space to fill the block. + if nx == 0 { + d.nullt = true + } + d.t -= 440 - nx<<3 + d.Write(pad[0 : 55-nx]) + } else { + // Need 2 compressions. + d.t -= 512 - nx<<3 + d.Write(pad[0 : 64-nx]) + d.t -= 440 + d.Write(pad[1:56]) + d.nullt = true + } + if d.hashSize == 224 { + d.Write([]byte{0x00}) + } else { + d.Write([]byte{0x01}) + } + d.t -= 8 + } + d.t -= 64 + d.Write(len) + + out := make([]byte, d.Size()) + j := 0 + for _, s := range d.h[:d.hashSize>>5] { + out[j+0] = byte(s >> 24) + out[j+1] = byte(s >> 16) + out[j+2] = byte(s >> 8) + out[j+3] = byte(s >> 0) + j += 4 + } + return append(in, out...) +} + +func (d *digest) setSalt(s []byte) { + if len(s) != 16 { + panic("salt length must be 16 bytes") + } + d.s[0] = uint32(s[0])<<24 | uint32(s[1])<<16 | uint32(s[2])<<8 | uint32(s[3]) + d.s[1] = uint32(s[4])<<24 | uint32(s[5])<<16 | uint32(s[6])<<8 | uint32(s[7]) + d.s[2] = uint32(s[8])<<24 | uint32(s[9])<<16 | uint32(s[10])<<8 | uint32(s[11]) + d.s[3] = uint32(s[12])<<24 | uint32(s[13])<<16 | uint32(s[14])<<8 | uint32(s[15]) +} + +// New returns a new hash.Hash computing the BLAKE-256 checksum. +func New() hash.Hash { + return &digest{ + hashSize: 256, + h: iv256, + } +} + +// NewSalt is like New but initializes salt with the given 16-byte slice. +func NewSalt(salt []byte) hash.Hash { + d := &digest{ + hashSize: 256, + h: iv256, + } + d.setSalt(salt) + return d +} + +// New224 returns a new hash.Hash computing the BLAKE-224 checksum. +func New224() hash.Hash { + return &digest{ + hashSize: 224, + h: iv224, + } +} + +// New224Salt is like New224 but initializes salt with the given 16-byte slice. +func New224Salt(salt []byte) hash.Hash { + d := &digest{ + hashSize: 224, + h: iv224, + } + d.setSalt(salt) + return d +} diff --git a/contrib/backends/nntpchand/src/vendor/github.com/dchest/blake256/blake256_test.go b/contrib/backends/nntpchand/src/vendor/github.com/dchest/blake256/blake256_test.go new file mode 100644 index 0000000..1908133 --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/dchest/blake256/blake256_test.go @@ -0,0 +1,188 @@ +// Written in 2011-2012 by Dmitry Chestnykh. +// +// To the extent possible under law, the author have dedicated all copyright +// and related and neighboring rights to this software to the public domain +// worldwide. This software is distributed without any warranty. +// http://creativecommons.org/publicdomain/zero/1.0/ + +package blake256 + +import ( + "bytes" + "fmt" + "hash" + "testing" +) + +func Test256C(t *testing.T) { + // Test as in C program. + var hashes = [][]byte{ + { + 0x0C, 0xE8, 0xD4, 0xEF, 0x4D, 0xD7, 0xCD, 0x8D, + 0x62, 0xDF, 0xDE, 0xD9, 0xD4, 0xED, 0xB0, 0xA7, + 0x74, 0xAE, 0x6A, 0x41, 0x92, 0x9A, 0x74, 0xDA, + 0x23, 0x10, 0x9E, 0x8F, 0x11, 0x13, 0x9C, 0x87, + }, + { + 0xD4, 0x19, 0xBA, 0xD3, 0x2D, 0x50, 0x4F, 0xB7, + 0xD4, 0x4D, 0x46, 0x0C, 0x42, 0xC5, 0x59, 0x3F, + 0xE5, 0x44, 0xFA, 0x4C, 0x13, 0x5D, 0xEC, 0x31, + 0xE2, 0x1B, 0xD9, 0xAB, 0xDC, 0xC2, 0x2D, 0x41, + }, + } + data := make([]byte, 72) + + h := New() + h.Write(data[:1]) + sum := h.Sum(nil) + if !bytes.Equal(hashes[0], sum) { + t.Errorf("0: expected %X, got %X", hashes[0], sum) + } + + // Try to continue hashing. + h.Write(data[1:]) + sum = h.Sum(nil) + if !bytes.Equal(hashes[1], sum) { + t.Errorf("1(1): expected %X, got %X", hashes[1], sum) + } + + // Try with reset. + h.Reset() + h.Write(data) + sum = h.Sum(nil) + if !bytes.Equal(hashes[1], sum) { + t.Errorf("1(2): expected %X, got %X", hashes[1], sum) + } +} + +type blakeVector struct { + out, in string +} + +var vectors256 = []blakeVector{ + {"7576698ee9cad30173080678e5965916adbb11cb5245d386bf1ffda1cb26c9d7", + "The quick brown fox jumps over the lazy dog"}, + {"07663e00cf96fbc136cf7b1ee099c95346ba3920893d18cc8851f22ee2e36aa6", + "BLAKE"}, + {"716f6e863f744b9ac22c97ec7b76ea5f5908bc5b2f67c61510bfc4751384ea7a", + ""}, + {"18a393b4e62b1887a2edf79a5c5a5464daf5bbb976f4007bea16a73e4c1e198e", + "'BLAKE wins SHA-3! Hooray!!!' (I have time machine)"}, + {"fd7282ecc105ef201bb94663fc413db1b7696414682090015f17e309b835f1c2", + "Go"}, + {"1e75db2a709081f853c2229b65fd1558540aa5e7bd17b04b9a4b31989effa711", + "HELP! I'm trapped in hash!"}, + {"4181475cb0c22d58ae847e368e91b4669ea2d84bcd55dbf01fe24bae6571dd08", + `Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec a diam lectus. Sed sit amet ipsum mauris. Maecenas congue ligula ac quam viverra nec consectetur ante hendrerit. Donec et mollis dolor. Praesent et diam eget libero egestas mattis sit amet vitae augue. Nam tincidunt congue enim, ut porta lorem lacinia consectetur. Donec ut libero sed arcu vehicula ultricies a non tortor. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean ut gravida lorem. Ut turpis felis, pulvinar a semper sed, adipiscing id dolor. Pellentesque auctor nisi id magna consequat sagittis. Curabitur dapibus enim sit amet elit pharetra tincidunt feugiat nisl imperdiet. Ut convallis libero in urna ultrices accumsan. Donec sed odio eros. Donec viverra mi quis quam pulvinar at malesuada arcu rhoncus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. In rutrum accumsan ultricies. Mauris vitae nisi at sem facilisis semper ac in est.`, + }, + {"af95fffc7768821b1e08866a2f9f66916762bfc9d71c4acb5fd515f31fd6785a", // test with one padding byte + "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec a diam lectus. Sed sit amet ipsum mauris. Maecenas congu", + }, +} + +var vectors224 = []blakeVector{ + {"c8e92d7088ef87c1530aee2ad44dc720cc10589cc2ec58f95a15e51b", + "The quick brown fox jumps over the lazy dog"}, + {"cfb6848add73e1cb47994c4765df33b8f973702705a30a71fe4747a3", + "BLAKE"}, + {"7dc5313b1c04512a174bd6503b89607aecbee0903d40a8a569c94eed", + ""}, + {"dde9e442003c24495db607b17e07ec1f67396cc1907642a09a96594e", + "Go"}, + {"9f655b0a92d4155754fa35e055ce7c5e18eb56347081ea1e5158e751", + "Buffalo buffalo Buffalo buffalo buffalo buffalo Buffalo buffalo"}, +} + +func testVectors(t *testing.T, hashfunc func() hash.Hash, vectors []blakeVector) { + for i, v := range vectors { + h := hashfunc() + h.Write([]byte(v.in)) + res := fmt.Sprintf("%x", h.Sum(nil)) + if res != v.out { + t.Errorf("%d: expected %q, got %q", i, v.out, res) + } + } +} + +func Test256(t *testing.T) { + testVectors(t, New, vectors256) +} + +func Test224(t *testing.T) { + testVectors(t, New224, vectors224) +} + +var vectors256salt = []struct{ out, in, salt string }{ + {"561d6d0cfa3d31d5eedaf2d575f3942539b03522befc2a1196ba0e51af8992a8", + "", + "1234567890123456"}, + {"88cc11889bbbee42095337fe2153c591971f94fbf8fe540d3c7e9f1700ab2d0c", + "It's so salty out there!", + "SALTsaltSaltSALT"}, +} + +func TestSalt(t *testing.T) { + for i, v := range vectors256salt { + h := NewSalt([]byte(v.salt)) + h.Write([]byte(v.in)) + res := fmt.Sprintf("%x", h.Sum(nil)) + if res != v.out { + t.Errorf("%d: expected %q, got %q", i, v.out, res) + } + } + + // Check that passing bad salt length panics. + defer func() { + if err := recover(); err == nil { + t.Errorf("expected panic for bad salt length") + } + }() + NewSalt([]byte{1, 2, 3, 4, 5, 6, 7, 8}) +} + +func TestTwoWrites(t *testing.T) { + b := make([]byte, 65) + for i := range b { + b[i] = byte(i) + } + h1 := New() + h1.Write(b[:1]) + h1.Write(b[1:]) + sum1 := h1.Sum(nil) + + h2 := New() + h2.Write(b) + sum2 := h2.Sum(nil) + + if !bytes.Equal(sum1, sum2) { + t.Errorf("Result of two writes differs from a single write with the same bytes") + } +} + +var bench = New() +var buf = make([]byte, 8<<10) + +func BenchmarkHash1K(b *testing.B) { + b.SetBytes(1024) + for i := 0; i < b.N; i++ { + bench.Write(buf[:1024]) + } +} + +func BenchmarkHash8K(b *testing.B) { + b.SetBytes(int64(len(buf))) + for i := 0; i < b.N; i++ { + bench.Write(buf) + } +} + +func BenchmarkFull64(b *testing.B) { + b.SetBytes(64) + tmp := make([]byte, 32) + b.ResetTimer() + for i := 0; i < b.N; i++ { + bench.Reset() + bench.Write(buf[:64]) + bench.Sum(tmp[0:0]) + } +} diff --git a/contrib/backends/nntpchand/src/vendor/github.com/dchest/blake256/blake256block.go b/contrib/backends/nntpchand/src/vendor/github.com/dchest/blake256/blake256block.go new file mode 100644 index 0000000..49daf69 --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/dchest/blake256/blake256block.go @@ -0,0 +1,1681 @@ +// Written in 2011-2012 by Dmitry Chestnykh. +// +// To the extent possible under law, the author have dedicated all copyright +// and related and neighboring rights to this software to the public domain +// worldwide. This software is distributed without any warranty. +// http://creativecommons.org/publicdomain/zero/1.0/ + +// BLAKE-256 block step. +// In its own file so that a faster assembly or C version +// can be substituted easily. + +package blake256 + +const ( + cst0 = 0x243F6A88 + cst1 = 0x85A308D3 + cst2 = 0x13198A2E + cst3 = 0x03707344 + cst4 = 0xA4093822 + cst5 = 0x299F31D0 + cst6 = 0x082EFA98 + cst7 = 0xEC4E6C89 + cst8 = 0x452821E6 + cst9 = 0x38D01377 + cst10 = 0xBE5466CF + cst11 = 0x34E90C6C + cst12 = 0xC0AC29B7 + cst13 = 0xC97C50DD + cst14 = 0x3F84D5B5 + cst15 = 0xB5470917 +) + +func block(d *digest, p []uint8) { + h0, h1, h2, h3, h4, h5, h6, h7 := d.h[0], d.h[1], d.h[2], d.h[3], d.h[4], d.h[5], d.h[6], d.h[7] + s0, s1, s2, s3 := d.s[0], d.s[1], d.s[2], d.s[3] + + for len(p) >= BlockSize { + v0, v1, v2, v3, v4, v5, v6, v7 := h0, h1, h2, h3, h4, h5, h6, h7 + v8 := cst0 ^ s0 + v9 := cst1 ^ s1 + v10 := cst2 ^ s2 + v11 := cst3 ^ s3 + v12 := uint32(cst4) + v13 := uint32(cst5) + v14 := uint32(cst6) + v15 := uint32(cst7) + d.t += 512 + if !d.nullt { + v12 ^= uint32(d.t) + v13 ^= uint32(d.t) + v14 ^= uint32(d.t >> 32) + v15 ^= uint32(d.t >> 32) + } + var m [16]uint32 + + m[0] = uint32(p[0])<<24 | uint32(p[1])<<16 | uint32(p[2])<<8 | uint32(p[3]) + m[1] = uint32(p[4])<<24 | uint32(p[5])<<16 | uint32(p[6])<<8 | uint32(p[7]) + m[2] = uint32(p[8])<<24 | uint32(p[9])<<16 | uint32(p[10])<<8 | uint32(p[11]) + m[3] = uint32(p[12])<<24 | uint32(p[13])<<16 | uint32(p[14])<<8 | uint32(p[15]) + m[4] = uint32(p[16])<<24 | uint32(p[17])<<16 | uint32(p[18])<<8 | uint32(p[19]) + m[5] = uint32(p[20])<<24 | uint32(p[21])<<16 | uint32(p[22])<<8 | uint32(p[23]) + m[6] = uint32(p[24])<<24 | uint32(p[25])<<16 | uint32(p[26])<<8 | uint32(p[27]) + m[7] = uint32(p[28])<<24 | uint32(p[29])<<16 | uint32(p[30])<<8 | uint32(p[31]) + m[8] = uint32(p[32])<<24 | uint32(p[33])<<16 | uint32(p[34])<<8 | uint32(p[35]) + m[9] = uint32(p[36])<<24 | uint32(p[37])<<16 | uint32(p[38])<<8 | uint32(p[39]) + m[10] = uint32(p[40])<<24 | uint32(p[41])<<16 | uint32(p[42])<<8 | uint32(p[43]) + m[11] = uint32(p[44])<<24 | uint32(p[45])<<16 | uint32(p[46])<<8 | uint32(p[47]) + m[12] = uint32(p[48])<<24 | uint32(p[49])<<16 | uint32(p[50])<<8 | uint32(p[51]) + m[13] = uint32(p[52])<<24 | uint32(p[53])<<16 | uint32(p[54])<<8 | uint32(p[55]) + m[14] = uint32(p[56])<<24 | uint32(p[57])<<16 | uint32(p[58])<<8 | uint32(p[59]) + m[15] = uint32(p[60])<<24 | uint32(p[61])<<16 | uint32(p[62])<<8 | uint32(p[63]) + + // Round 1. + v0 += m[0] ^ cst1 + v0 += v4 + v12 ^= v0 + v12 = v12<<(32-16) | v12>>16 + v8 += v12 + v4 ^= v8 + v4 = v4<<(32-12) | v4>>12 + v1 += m[2] ^ cst3 + v1 += v5 + v13 ^= v1 + v13 = v13<<(32-16) | v13>>16 + v9 += v13 + v5 ^= v9 + v5 = v5<<(32-12) | v5>>12 + v2 += m[4] ^ cst5 + v2 += v6 + v14 ^= v2 + v14 = v14<<(32-16) | v14>>16 + v10 += v14 + v6 ^= v10 + v6 = v6<<(32-12) | v6>>12 + v3 += m[6] ^ cst7 + v3 += v7 + v15 ^= v3 + v15 = v15<<(32-16) | v15>>16 + v11 += v15 + v7 ^= v11 + v7 = v7<<(32-12) | v7>>12 + v2 += m[5] ^ cst4 + v2 += v6 + v14 ^= v2 + v14 = v14<<(32-8) | v14>>8 + v10 += v14 + v6 ^= v10 + v6 = v6<<(32-7) | v6>>7 + v3 += m[7] ^ cst6 + v3 += v7 + v15 ^= v3 + v15 = v15<<(32-8) | v15>>8 + v11 += v15 + v7 ^= v11 + v7 = v7<<(32-7) | v7>>7 + v1 += m[3] ^ cst2 + v1 += v5 + v13 ^= v1 + v13 = v13<<(32-8) | v13>>8 + v9 += v13 + v5 ^= v9 + v5 = v5<<(32-7) | v5>>7 + v0 += m[1] ^ cst0 + v0 += v4 + v12 ^= v0 + v12 = v12<<(32-8) | v12>>8 + v8 += v12 + v4 ^= v8 + v4 = v4<<(32-7) | v4>>7 + v0 += m[8] ^ cst9 + v0 += v5 + v15 ^= v0 + v15 = v15<<(32-16) | v15>>16 + v10 += v15 + v5 ^= v10 + v5 = v5<<(32-12) | v5>>12 + v1 += m[10] ^ cst11 + v1 += v6 + v12 ^= v1 + v12 = v12<<(32-16) | v12>>16 + v11 += v12 + v6 ^= v11 + v6 = v6<<(32-12) | v6>>12 + v2 += m[12] ^ cst13 + v2 += v7 + v13 ^= v2 + v13 = v13<<(32-16) | v13>>16 + v8 += v13 + v7 ^= v8 + v7 = v7<<(32-12) | v7>>12 + v3 += m[14] ^ cst15 + v3 += v4 + v14 ^= v3 + v14 = v14<<(32-16) | v14>>16 + v9 += v14 + v4 ^= v9 + v4 = v4<<(32-12) | v4>>12 + v2 += m[13] ^ cst12 + v2 += v7 + v13 ^= v2 + v13 = v13<<(32-8) | v13>>8 + v8 += v13 + v7 ^= v8 + v7 = v7<<(32-7) | v7>>7 + v3 += m[15] ^ cst14 + v3 += v4 + v14 ^= v3 + v14 = v14<<(32-8) | v14>>8 + v9 += v14 + v4 ^= v9 + v4 = v4<<(32-7) | v4>>7 + v1 += m[11] ^ cst10 + v1 += v6 + v12 ^= v1 + v12 = v12<<(32-8) | v12>>8 + v11 += v12 + v6 ^= v11 + v6 = v6<<(32-7) | v6>>7 + v0 += m[9] ^ cst8 + v0 += v5 + v15 ^= v0 + v15 = v15<<(32-8) | v15>>8 + v10 += v15 + v5 ^= v10 + v5 = v5<<(32-7) | v5>>7 + + // Round 2. + v0 += m[14] ^ cst10 + v0 += v4 + v12 ^= v0 + v12 = v12<<(32-16) | v12>>16 + v8 += v12 + v4 ^= v8 + v4 = v4<<(32-12) | v4>>12 + v1 += m[4] ^ cst8 + v1 += v5 + v13 ^= v1 + v13 = v13<<(32-16) | v13>>16 + v9 += v13 + v5 ^= v9 + v5 = v5<<(32-12) | v5>>12 + v2 += m[9] ^ cst15 + v2 += v6 + v14 ^= v2 + v14 = v14<<(32-16) | v14>>16 + v10 += v14 + v6 ^= v10 + v6 = v6<<(32-12) | v6>>12 + v3 += m[13] ^ cst6 + v3 += v7 + v15 ^= v3 + v15 = v15<<(32-16) | v15>>16 + v11 += v15 + v7 ^= v11 + v7 = v7<<(32-12) | v7>>12 + v2 += m[15] ^ cst9 + v2 += v6 + v14 ^= v2 + v14 = v14<<(32-8) | v14>>8 + v10 += v14 + v6 ^= v10 + v6 = v6<<(32-7) | v6>>7 + v3 += m[6] ^ cst13 + v3 += v7 + v15 ^= v3 + v15 = v15<<(32-8) | v15>>8 + v11 += v15 + v7 ^= v11 + v7 = v7<<(32-7) | v7>>7 + v1 += m[8] ^ cst4 + v1 += v5 + v13 ^= v1 + v13 = v13<<(32-8) | v13>>8 + v9 += v13 + v5 ^= v9 + v5 = v5<<(32-7) | v5>>7 + v0 += m[10] ^ cst14 + v0 += v4 + v12 ^= v0 + v12 = v12<<(32-8) | v12>>8 + v8 += v12 + v4 ^= v8 + v4 = v4<<(32-7) | v4>>7 + v0 += m[1] ^ cst12 + v0 += v5 + v15 ^= v0 + v15 = v15<<(32-16) | v15>>16 + v10 += v15 + v5 ^= v10 + v5 = v5<<(32-12) | v5>>12 + v1 += m[0] ^ cst2 + v1 += v6 + v12 ^= v1 + v12 = v12<<(32-16) | v12>>16 + v11 += v12 + v6 ^= v11 + v6 = v6<<(32-12) | v6>>12 + v2 += m[11] ^ cst7 + v2 += v7 + v13 ^= v2 + v13 = v13<<(32-16) | v13>>16 + v8 += v13 + v7 ^= v8 + v7 = v7<<(32-12) | v7>>12 + v3 += m[5] ^ cst3 + v3 += v4 + v14 ^= v3 + v14 = v14<<(32-16) | v14>>16 + v9 += v14 + v4 ^= v9 + v4 = v4<<(32-12) | v4>>12 + v2 += m[7] ^ cst11 + v2 += v7 + v13 ^= v2 + v13 = v13<<(32-8) | v13>>8 + v8 += v13 + v7 ^= v8 + v7 = v7<<(32-7) | v7>>7 + v3 += m[3] ^ cst5 + v3 += v4 + v14 ^= v3 + v14 = v14<<(32-8) | v14>>8 + v9 += v14 + v4 ^= v9 + v4 = v4<<(32-7) | v4>>7 + v1 += m[2] ^ cst0 + v1 += v6 + v12 ^= v1 + v12 = v12<<(32-8) | v12>>8 + v11 += v12 + v6 ^= v11 + v6 = v6<<(32-7) | v6>>7 + v0 += m[12] ^ cst1 + v0 += v5 + v15 ^= v0 + v15 = v15<<(32-8) | v15>>8 + v10 += v15 + v5 ^= v10 + v5 = v5<<(32-7) | v5>>7 + + // Round 3. + v0 += m[11] ^ cst8 + v0 += v4 + v12 ^= v0 + v12 = v12<<(32-16) | v12>>16 + v8 += v12 + v4 ^= v8 + v4 = v4<<(32-12) | v4>>12 + v1 += m[12] ^ cst0 + v1 += v5 + v13 ^= v1 + v13 = v13<<(32-16) | v13>>16 + v9 += v13 + v5 ^= v9 + v5 = v5<<(32-12) | v5>>12 + v2 += m[5] ^ cst2 + v2 += v6 + v14 ^= v2 + v14 = v14<<(32-16) | v14>>16 + v10 += v14 + v6 ^= v10 + v6 = v6<<(32-12) | v6>>12 + v3 += m[15] ^ cst13 + v3 += v7 + v15 ^= v3 + v15 = v15<<(32-16) | v15>>16 + v11 += v15 + v7 ^= v11 + v7 = v7<<(32-12) | v7>>12 + v2 += m[2] ^ cst5 + v2 += v6 + v14 ^= v2 + v14 = v14<<(32-8) | v14>>8 + v10 += v14 + v6 ^= v10 + v6 = v6<<(32-7) | v6>>7 + v3 += m[13] ^ cst15 + v3 += v7 + v15 ^= v3 + v15 = v15<<(32-8) | v15>>8 + v11 += v15 + v7 ^= v11 + v7 = v7<<(32-7) | v7>>7 + v1 += m[0] ^ cst12 + v1 += v5 + v13 ^= v1 + v13 = v13<<(32-8) | v13>>8 + v9 += v13 + v5 ^= v9 + v5 = v5<<(32-7) | v5>>7 + v0 += m[8] ^ cst11 + v0 += v4 + v12 ^= v0 + v12 = v12<<(32-8) | v12>>8 + v8 += v12 + v4 ^= v8 + v4 = v4<<(32-7) | v4>>7 + v0 += m[10] ^ cst14 + v0 += v5 + v15 ^= v0 + v15 = v15<<(32-16) | v15>>16 + v10 += v15 + v5 ^= v10 + v5 = v5<<(32-12) | v5>>12 + v1 += m[3] ^ cst6 + v1 += v6 + v12 ^= v1 + v12 = v12<<(32-16) | v12>>16 + v11 += v12 + v6 ^= v11 + v6 = v6<<(32-12) | v6>>12 + v2 += m[7] ^ cst1 + v2 += v7 + v13 ^= v2 + v13 = v13<<(32-16) | v13>>16 + v8 += v13 + v7 ^= v8 + v7 = v7<<(32-12) | v7>>12 + v3 += m[9] ^ cst4 + v3 += v4 + v14 ^= v3 + v14 = v14<<(32-16) | v14>>16 + v9 += v14 + v4 ^= v9 + v4 = v4<<(32-12) | v4>>12 + v2 += m[1] ^ cst7 + v2 += v7 + v13 ^= v2 + v13 = v13<<(32-8) | v13>>8 + v8 += v13 + v7 ^= v8 + v7 = v7<<(32-7) | v7>>7 + v3 += m[4] ^ cst9 + v3 += v4 + v14 ^= v3 + v14 = v14<<(32-8) | v14>>8 + v9 += v14 + v4 ^= v9 + v4 = v4<<(32-7) | v4>>7 + v1 += m[6] ^ cst3 + v1 += v6 + v12 ^= v1 + v12 = v12<<(32-8) | v12>>8 + v11 += v12 + v6 ^= v11 + v6 = v6<<(32-7) | v6>>7 + v0 += m[14] ^ cst10 + v0 += v5 + v15 ^= v0 + v15 = v15<<(32-8) | v15>>8 + v10 += v15 + v5 ^= v10 + v5 = v5<<(32-7) | v5>>7 + + // Round 4. + v0 += m[7] ^ cst9 + v0 += v4 + v12 ^= v0 + v12 = v12<<(32-16) | v12>>16 + v8 += v12 + v4 ^= v8 + v4 = v4<<(32-12) | v4>>12 + v1 += m[3] ^ cst1 + v1 += v5 + v13 ^= v1 + v13 = v13<<(32-16) | v13>>16 + v9 += v13 + v5 ^= v9 + v5 = v5<<(32-12) | v5>>12 + v2 += m[13] ^ cst12 + v2 += v6 + v14 ^= v2 + v14 = v14<<(32-16) | v14>>16 + v10 += v14 + v6 ^= v10 + v6 = v6<<(32-12) | v6>>12 + v3 += m[11] ^ cst14 + v3 += v7 + v15 ^= v3 + v15 = v15<<(32-16) | v15>>16 + v11 += v15 + v7 ^= v11 + v7 = v7<<(32-12) | v7>>12 + v2 += m[12] ^ cst13 + v2 += v6 + v14 ^= v2 + v14 = v14<<(32-8) | v14>>8 + v10 += v14 + v6 ^= v10 + v6 = v6<<(32-7) | v6>>7 + v3 += m[14] ^ cst11 + v3 += v7 + v15 ^= v3 + v15 = v15<<(32-8) | v15>>8 + v11 += v15 + v7 ^= v11 + v7 = v7<<(32-7) | v7>>7 + v1 += m[1] ^ cst3 + v1 += v5 + v13 ^= v1 + v13 = v13<<(32-8) | v13>>8 + v9 += v13 + v5 ^= v9 + v5 = v5<<(32-7) | v5>>7 + v0 += m[9] ^ cst7 + v0 += v4 + v12 ^= v0 + v12 = v12<<(32-8) | v12>>8 + v8 += v12 + v4 ^= v8 + v4 = v4<<(32-7) | v4>>7 + v0 += m[2] ^ cst6 + v0 += v5 + v15 ^= v0 + v15 = v15<<(32-16) | v15>>16 + v10 += v15 + v5 ^= v10 + v5 = v5<<(32-12) | v5>>12 + v1 += m[5] ^ cst10 + v1 += v6 + v12 ^= v1 + v12 = v12<<(32-16) | v12>>16 + v11 += v12 + v6 ^= v11 + v6 = v6<<(32-12) | v6>>12 + v2 += m[4] ^ cst0 + v2 += v7 + v13 ^= v2 + v13 = v13<<(32-16) | v13>>16 + v8 += v13 + v7 ^= v8 + v7 = v7<<(32-12) | v7>>12 + v3 += m[15] ^ cst8 + v3 += v4 + v14 ^= v3 + v14 = v14<<(32-16) | v14>>16 + v9 += v14 + v4 ^= v9 + v4 = v4<<(32-12) | v4>>12 + v2 += m[0] ^ cst4 + v2 += v7 + v13 ^= v2 + v13 = v13<<(32-8) | v13>>8 + v8 += v13 + v7 ^= v8 + v7 = v7<<(32-7) | v7>>7 + v3 += m[8] ^ cst15 + v3 += v4 + v14 ^= v3 + v14 = v14<<(32-8) | v14>>8 + v9 += v14 + v4 ^= v9 + v4 = v4<<(32-7) | v4>>7 + v1 += m[10] ^ cst5 + v1 += v6 + v12 ^= v1 + v12 = v12<<(32-8) | v12>>8 + v11 += v12 + v6 ^= v11 + v6 = v6<<(32-7) | v6>>7 + v0 += m[6] ^ cst2 + v0 += v5 + v15 ^= v0 + v15 = v15<<(32-8) | v15>>8 + v10 += v15 + v5 ^= v10 + v5 = v5<<(32-7) | v5>>7 + + // Round 5. + v0 += m[9] ^ cst0 + v0 += v4 + v12 ^= v0 + v12 = v12<<(32-16) | v12>>16 + v8 += v12 + v4 ^= v8 + v4 = v4<<(32-12) | v4>>12 + v1 += m[5] ^ cst7 + v1 += v5 + v13 ^= v1 + v13 = v13<<(32-16) | v13>>16 + v9 += v13 + v5 ^= v9 + v5 = v5<<(32-12) | v5>>12 + v2 += m[2] ^ cst4 + v2 += v6 + v14 ^= v2 + v14 = v14<<(32-16) | v14>>16 + v10 += v14 + v6 ^= v10 + v6 = v6<<(32-12) | v6>>12 + v3 += m[10] ^ cst15 + v3 += v7 + v15 ^= v3 + v15 = v15<<(32-16) | v15>>16 + v11 += v15 + v7 ^= v11 + v7 = v7<<(32-12) | v7>>12 + v2 += m[4] ^ cst2 + v2 += v6 + v14 ^= v2 + v14 = v14<<(32-8) | v14>>8 + v10 += v14 + v6 ^= v10 + v6 = v6<<(32-7) | v6>>7 + v3 += m[15] ^ cst10 + v3 += v7 + v15 ^= v3 + v15 = v15<<(32-8) | v15>>8 + v11 += v15 + v7 ^= v11 + v7 = v7<<(32-7) | v7>>7 + v1 += m[7] ^ cst5 + v1 += v5 + v13 ^= v1 + v13 = v13<<(32-8) | v13>>8 + v9 += v13 + v5 ^= v9 + v5 = v5<<(32-7) | v5>>7 + v0 += m[0] ^ cst9 + v0 += v4 + v12 ^= v0 + v12 = v12<<(32-8) | v12>>8 + v8 += v12 + v4 ^= v8 + v4 = v4<<(32-7) | v4>>7 + v0 += m[14] ^ cst1 + v0 += v5 + v15 ^= v0 + v15 = v15<<(32-16) | v15>>16 + v10 += v15 + v5 ^= v10 + v5 = v5<<(32-12) | v5>>12 + v1 += m[11] ^ cst12 + v1 += v6 + v12 ^= v1 + v12 = v12<<(32-16) | v12>>16 + v11 += v12 + v6 ^= v11 + v6 = v6<<(32-12) | v6>>12 + v2 += m[6] ^ cst8 + v2 += v7 + v13 ^= v2 + v13 = v13<<(32-16) | v13>>16 + v8 += v13 + v7 ^= v8 + v7 = v7<<(32-12) | v7>>12 + v3 += m[3] ^ cst13 + v3 += v4 + v14 ^= v3 + v14 = v14<<(32-16) | v14>>16 + v9 += v14 + v4 ^= v9 + v4 = v4<<(32-12) | v4>>12 + v2 += m[8] ^ cst6 + v2 += v7 + v13 ^= v2 + v13 = v13<<(32-8) | v13>>8 + v8 += v13 + v7 ^= v8 + v7 = v7<<(32-7) | v7>>7 + v3 += m[13] ^ cst3 + v3 += v4 + v14 ^= v3 + v14 = v14<<(32-8) | v14>>8 + v9 += v14 + v4 ^= v9 + v4 = v4<<(32-7) | v4>>7 + v1 += m[12] ^ cst11 + v1 += v6 + v12 ^= v1 + v12 = v12<<(32-8) | v12>>8 + v11 += v12 + v6 ^= v11 + v6 = v6<<(32-7) | v6>>7 + v0 += m[1] ^ cst14 + v0 += v5 + v15 ^= v0 + v15 = v15<<(32-8) | v15>>8 + v10 += v15 + v5 ^= v10 + v5 = v5<<(32-7) | v5>>7 + + // Round 6. + v0 += m[2] ^ cst12 + v0 += v4 + v12 ^= v0 + v12 = v12<<(32-16) | v12>>16 + v8 += v12 + v4 ^= v8 + v4 = v4<<(32-12) | v4>>12 + v1 += m[6] ^ cst10 + v1 += v5 + v13 ^= v1 + v13 = v13<<(32-16) | v13>>16 + v9 += v13 + v5 ^= v9 + v5 = v5<<(32-12) | v5>>12 + v2 += m[0] ^ cst11 + v2 += v6 + v14 ^= v2 + v14 = v14<<(32-16) | v14>>16 + v10 += v14 + v6 ^= v10 + v6 = v6<<(32-12) | v6>>12 + v3 += m[8] ^ cst3 + v3 += v7 + v15 ^= v3 + v15 = v15<<(32-16) | v15>>16 + v11 += v15 + v7 ^= v11 + v7 = v7<<(32-12) | v7>>12 + v2 += m[11] ^ cst0 + v2 += v6 + v14 ^= v2 + v14 = v14<<(32-8) | v14>>8 + v10 += v14 + v6 ^= v10 + v6 = v6<<(32-7) | v6>>7 + v3 += m[3] ^ cst8 + v3 += v7 + v15 ^= v3 + v15 = v15<<(32-8) | v15>>8 + v11 += v15 + v7 ^= v11 + v7 = v7<<(32-7) | v7>>7 + v1 += m[10] ^ cst6 + v1 += v5 + v13 ^= v1 + v13 = v13<<(32-8) | v13>>8 + v9 += v13 + v5 ^= v9 + v5 = v5<<(32-7) | v5>>7 + v0 += m[12] ^ cst2 + v0 += v4 + v12 ^= v0 + v12 = v12<<(32-8) | v12>>8 + v8 += v12 + v4 ^= v8 + v4 = v4<<(32-7) | v4>>7 + v0 += m[4] ^ cst13 + v0 += v5 + v15 ^= v0 + v15 = v15<<(32-16) | v15>>16 + v10 += v15 + v5 ^= v10 + v5 = v5<<(32-12) | v5>>12 + v1 += m[7] ^ cst5 + v1 += v6 + v12 ^= v1 + v12 = v12<<(32-16) | v12>>16 + v11 += v12 + v6 ^= v11 + v6 = v6<<(32-12) | v6>>12 + v2 += m[15] ^ cst14 + v2 += v7 + v13 ^= v2 + v13 = v13<<(32-16) | v13>>16 + v8 += v13 + v7 ^= v8 + v7 = v7<<(32-12) | v7>>12 + v3 += m[1] ^ cst9 + v3 += v4 + v14 ^= v3 + v14 = v14<<(32-16) | v14>>16 + v9 += v14 + v4 ^= v9 + v4 = v4<<(32-12) | v4>>12 + v2 += m[14] ^ cst15 + v2 += v7 + v13 ^= v2 + v13 = v13<<(32-8) | v13>>8 + v8 += v13 + v7 ^= v8 + v7 = v7<<(32-7) | v7>>7 + v3 += m[9] ^ cst1 + v3 += v4 + v14 ^= v3 + v14 = v14<<(32-8) | v14>>8 + v9 += v14 + v4 ^= v9 + v4 = v4<<(32-7) | v4>>7 + v1 += m[5] ^ cst7 + v1 += v6 + v12 ^= v1 + v12 = v12<<(32-8) | v12>>8 + v11 += v12 + v6 ^= v11 + v6 = v6<<(32-7) | v6>>7 + v0 += m[13] ^ cst4 + v0 += v5 + v15 ^= v0 + v15 = v15<<(32-8) | v15>>8 + v10 += v15 + v5 ^= v10 + v5 = v5<<(32-7) | v5>>7 + + // Round 7. + v0 += m[12] ^ cst5 + v0 += v4 + v12 ^= v0 + v12 = v12<<(32-16) | v12>>16 + v8 += v12 + v4 ^= v8 + v4 = v4<<(32-12) | v4>>12 + v1 += m[1] ^ cst15 + v1 += v5 + v13 ^= v1 + v13 = v13<<(32-16) | v13>>16 + v9 += v13 + v5 ^= v9 + v5 = v5<<(32-12) | v5>>12 + v2 += m[14] ^ cst13 + v2 += v6 + v14 ^= v2 + v14 = v14<<(32-16) | v14>>16 + v10 += v14 + v6 ^= v10 + v6 = v6<<(32-12) | v6>>12 + v3 += m[4] ^ cst10 + v3 += v7 + v15 ^= v3 + v15 = v15<<(32-16) | v15>>16 + v11 += v15 + v7 ^= v11 + v7 = v7<<(32-12) | v7>>12 + v2 += m[13] ^ cst14 + v2 += v6 + v14 ^= v2 + v14 = v14<<(32-8) | v14>>8 + v10 += v14 + v6 ^= v10 + v6 = v6<<(32-7) | v6>>7 + v3 += m[10] ^ cst4 + v3 += v7 + v15 ^= v3 + v15 = v15<<(32-8) | v15>>8 + v11 += v15 + v7 ^= v11 + v7 = v7<<(32-7) | v7>>7 + v1 += m[15] ^ cst1 + v1 += v5 + v13 ^= v1 + v13 = v13<<(32-8) | v13>>8 + v9 += v13 + v5 ^= v9 + v5 = v5<<(32-7) | v5>>7 + v0 += m[5] ^ cst12 + v0 += v4 + v12 ^= v0 + v12 = v12<<(32-8) | v12>>8 + v8 += v12 + v4 ^= v8 + v4 = v4<<(32-7) | v4>>7 + v0 += m[0] ^ cst7 + v0 += v5 + v15 ^= v0 + v15 = v15<<(32-16) | v15>>16 + v10 += v15 + v5 ^= v10 + v5 = v5<<(32-12) | v5>>12 + v1 += m[6] ^ cst3 + v1 += v6 + v12 ^= v1 + v12 = v12<<(32-16) | v12>>16 + v11 += v12 + v6 ^= v11 + v6 = v6<<(32-12) | v6>>12 + v2 += m[9] ^ cst2 + v2 += v7 + v13 ^= v2 + v13 = v13<<(32-16) | v13>>16 + v8 += v13 + v7 ^= v8 + v7 = v7<<(32-12) | v7>>12 + v3 += m[8] ^ cst11 + v3 += v4 + v14 ^= v3 + v14 = v14<<(32-16) | v14>>16 + v9 += v14 + v4 ^= v9 + v4 = v4<<(32-12) | v4>>12 + v2 += m[2] ^ cst9 + v2 += v7 + v13 ^= v2 + v13 = v13<<(32-8) | v13>>8 + v8 += v13 + v7 ^= v8 + v7 = v7<<(32-7) | v7>>7 + v3 += m[11] ^ cst8 + v3 += v4 + v14 ^= v3 + v14 = v14<<(32-8) | v14>>8 + v9 += v14 + v4 ^= v9 + v4 = v4<<(32-7) | v4>>7 + v1 += m[3] ^ cst6 + v1 += v6 + v12 ^= v1 + v12 = v12<<(32-8) | v12>>8 + v11 += v12 + v6 ^= v11 + v6 = v6<<(32-7) | v6>>7 + v0 += m[7] ^ cst0 + v0 += v5 + v15 ^= v0 + v15 = v15<<(32-8) | v15>>8 + v10 += v15 + v5 ^= v10 + v5 = v5<<(32-7) | v5>>7 + + // Round 8. + v0 += m[13] ^ cst11 + v0 += v4 + v12 ^= v0 + v12 = v12<<(32-16) | v12>>16 + v8 += v12 + v4 ^= v8 + v4 = v4<<(32-12) | v4>>12 + v1 += m[7] ^ cst14 + v1 += v5 + v13 ^= v1 + v13 = v13<<(32-16) | v13>>16 + v9 += v13 + v5 ^= v9 + v5 = v5<<(32-12) | v5>>12 + v2 += m[12] ^ cst1 + v2 += v6 + v14 ^= v2 + v14 = v14<<(32-16) | v14>>16 + v10 += v14 + v6 ^= v10 + v6 = v6<<(32-12) | v6>>12 + v3 += m[3] ^ cst9 + v3 += v7 + v15 ^= v3 + v15 = v15<<(32-16) | v15>>16 + v11 += v15 + v7 ^= v11 + v7 = v7<<(32-12) | v7>>12 + v2 += m[1] ^ cst12 + v2 += v6 + v14 ^= v2 + v14 = v14<<(32-8) | v14>>8 + v10 += v14 + v6 ^= v10 + v6 = v6<<(32-7) | v6>>7 + v3 += m[9] ^ cst3 + v3 += v7 + v15 ^= v3 + v15 = v15<<(32-8) | v15>>8 + v11 += v15 + v7 ^= v11 + v7 = v7<<(32-7) | v7>>7 + v1 += m[14] ^ cst7 + v1 += v5 + v13 ^= v1 + v13 = v13<<(32-8) | v13>>8 + v9 += v13 + v5 ^= v9 + v5 = v5<<(32-7) | v5>>7 + v0 += m[11] ^ cst13 + v0 += v4 + v12 ^= v0 + v12 = v12<<(32-8) | v12>>8 + v8 += v12 + v4 ^= v8 + v4 = v4<<(32-7) | v4>>7 + v0 += m[5] ^ cst0 + v0 += v5 + v15 ^= v0 + v15 = v15<<(32-16) | v15>>16 + v10 += v15 + v5 ^= v10 + v5 = v5<<(32-12) | v5>>12 + v1 += m[15] ^ cst4 + v1 += v6 + v12 ^= v1 + v12 = v12<<(32-16) | v12>>16 + v11 += v12 + v6 ^= v11 + v6 = v6<<(32-12) | v6>>12 + v2 += m[8] ^ cst6 + v2 += v7 + v13 ^= v2 + v13 = v13<<(32-16) | v13>>16 + v8 += v13 + v7 ^= v8 + v7 = v7<<(32-12) | v7>>12 + v3 += m[2] ^ cst10 + v3 += v4 + v14 ^= v3 + v14 = v14<<(32-16) | v14>>16 + v9 += v14 + v4 ^= v9 + v4 = v4<<(32-12) | v4>>12 + v2 += m[6] ^ cst8 + v2 += v7 + v13 ^= v2 + v13 = v13<<(32-8) | v13>>8 + v8 += v13 + v7 ^= v8 + v7 = v7<<(32-7) | v7>>7 + v3 += m[10] ^ cst2 + v3 += v4 + v14 ^= v3 + v14 = v14<<(32-8) | v14>>8 + v9 += v14 + v4 ^= v9 + v4 = v4<<(32-7) | v4>>7 + v1 += m[4] ^ cst15 + v1 += v6 + v12 ^= v1 + v12 = v12<<(32-8) | v12>>8 + v11 += v12 + v6 ^= v11 + v6 = v6<<(32-7) | v6>>7 + v0 += m[0] ^ cst5 + v0 += v5 + v15 ^= v0 + v15 = v15<<(32-8) | v15>>8 + v10 += v15 + v5 ^= v10 + v5 = v5<<(32-7) | v5>>7 + + // Round 9. + v0 += m[6] ^ cst15 + v0 += v4 + v12 ^= v0 + v12 = v12<<(32-16) | v12>>16 + v8 += v12 + v4 ^= v8 + v4 = v4<<(32-12) | v4>>12 + v1 += m[14] ^ cst9 + v1 += v5 + v13 ^= v1 + v13 = v13<<(32-16) | v13>>16 + v9 += v13 + v5 ^= v9 + v5 = v5<<(32-12) | v5>>12 + v2 += m[11] ^ cst3 + v2 += v6 + v14 ^= v2 + v14 = v14<<(32-16) | v14>>16 + v10 += v14 + v6 ^= v10 + v6 = v6<<(32-12) | v6>>12 + v3 += m[0] ^ cst8 + v3 += v7 + v15 ^= v3 + v15 = v15<<(32-16) | v15>>16 + v11 += v15 + v7 ^= v11 + v7 = v7<<(32-12) | v7>>12 + v2 += m[3] ^ cst11 + v2 += v6 + v14 ^= v2 + v14 = v14<<(32-8) | v14>>8 + v10 += v14 + v6 ^= v10 + v6 = v6<<(32-7) | v6>>7 + v3 += m[8] ^ cst0 + v3 += v7 + v15 ^= v3 + v15 = v15<<(32-8) | v15>>8 + v11 += v15 + v7 ^= v11 + v7 = v7<<(32-7) | v7>>7 + v1 += m[9] ^ cst14 + v1 += v5 + v13 ^= v1 + v13 = v13<<(32-8) | v13>>8 + v9 += v13 + v5 ^= v9 + v5 = v5<<(32-7) | v5>>7 + v0 += m[15] ^ cst6 + v0 += v4 + v12 ^= v0 + v12 = v12<<(32-8) | v12>>8 + v8 += v12 + v4 ^= v8 + v4 = v4<<(32-7) | v4>>7 + v0 += m[12] ^ cst2 + v0 += v5 + v15 ^= v0 + v15 = v15<<(32-16) | v15>>16 + v10 += v15 + v5 ^= v10 + v5 = v5<<(32-12) | v5>>12 + v1 += m[13] ^ cst7 + v1 += v6 + v12 ^= v1 + v12 = v12<<(32-16) | v12>>16 + v11 += v12 + v6 ^= v11 + v6 = v6<<(32-12) | v6>>12 + v2 += m[1] ^ cst4 + v2 += v7 + v13 ^= v2 + v13 = v13<<(32-16) | v13>>16 + v8 += v13 + v7 ^= v8 + v7 = v7<<(32-12) | v7>>12 + v3 += m[10] ^ cst5 + v3 += v4 + v14 ^= v3 + v14 = v14<<(32-16) | v14>>16 + v9 += v14 + v4 ^= v9 + v4 = v4<<(32-12) | v4>>12 + v2 += m[4] ^ cst1 + v2 += v7 + v13 ^= v2 + v13 = v13<<(32-8) | v13>>8 + v8 += v13 + v7 ^= v8 + v7 = v7<<(32-7) | v7>>7 + v3 += m[5] ^ cst10 + v3 += v4 + v14 ^= v3 + v14 = v14<<(32-8) | v14>>8 + v9 += v14 + v4 ^= v9 + v4 = v4<<(32-7) | v4>>7 + v1 += m[7] ^ cst13 + v1 += v6 + v12 ^= v1 + v12 = v12<<(32-8) | v12>>8 + v11 += v12 + v6 ^= v11 + v6 = v6<<(32-7) | v6>>7 + v0 += m[2] ^ cst12 + v0 += v5 + v15 ^= v0 + v15 = v15<<(32-8) | v15>>8 + v10 += v15 + v5 ^= v10 + v5 = v5<<(32-7) | v5>>7 + + // Round 10. + v0 += m[10] ^ cst2 + v0 += v4 + v12 ^= v0 + v12 = v12<<(32-16) | v12>>16 + v8 += v12 + v4 ^= v8 + v4 = v4<<(32-12) | v4>>12 + v1 += m[8] ^ cst4 + v1 += v5 + v13 ^= v1 + v13 = v13<<(32-16) | v13>>16 + v9 += v13 + v5 ^= v9 + v5 = v5<<(32-12) | v5>>12 + v2 += m[7] ^ cst6 + v2 += v6 + v14 ^= v2 + v14 = v14<<(32-16) | v14>>16 + v10 += v14 + v6 ^= v10 + v6 = v6<<(32-12) | v6>>12 + v3 += m[1] ^ cst5 + v3 += v7 + v15 ^= v3 + v15 = v15<<(32-16) | v15>>16 + v11 += v15 + v7 ^= v11 + v7 = v7<<(32-12) | v7>>12 + v2 += m[6] ^ cst7 + v2 += v6 + v14 ^= v2 + v14 = v14<<(32-8) | v14>>8 + v10 += v14 + v6 ^= v10 + v6 = v6<<(32-7) | v6>>7 + v3 += m[5] ^ cst1 + v3 += v7 + v15 ^= v3 + v15 = v15<<(32-8) | v15>>8 + v11 += v15 + v7 ^= v11 + v7 = v7<<(32-7) | v7>>7 + v1 += m[4] ^ cst8 + v1 += v5 + v13 ^= v1 + v13 = v13<<(32-8) | v13>>8 + v9 += v13 + v5 ^= v9 + v5 = v5<<(32-7) | v5>>7 + v0 += m[2] ^ cst10 + v0 += v4 + v12 ^= v0 + v12 = v12<<(32-8) | v12>>8 + v8 += v12 + v4 ^= v8 + v4 = v4<<(32-7) | v4>>7 + v0 += m[15] ^ cst11 + v0 += v5 + v15 ^= v0 + v15 = v15<<(32-16) | v15>>16 + v10 += v15 + v5 ^= v10 + v5 = v5<<(32-12) | v5>>12 + v1 += m[9] ^ cst14 + v1 += v6 + v12 ^= v1 + v12 = v12<<(32-16) | v12>>16 + v11 += v12 + v6 ^= v11 + v6 = v6<<(32-12) | v6>>12 + v2 += m[3] ^ cst12 + v2 += v7 + v13 ^= v2 + v13 = v13<<(32-16) | v13>>16 + v8 += v13 + v7 ^= v8 + v7 = v7<<(32-12) | v7>>12 + v3 += m[13] ^ cst0 + v3 += v4 + v14 ^= v3 + v14 = v14<<(32-16) | v14>>16 + v9 += v14 + v4 ^= v9 + v4 = v4<<(32-12) | v4>>12 + v2 += m[12] ^ cst3 + v2 += v7 + v13 ^= v2 + v13 = v13<<(32-8) | v13>>8 + v8 += v13 + v7 ^= v8 + v7 = v7<<(32-7) | v7>>7 + v3 += m[0] ^ cst13 + v3 += v4 + v14 ^= v3 + v14 = v14<<(32-8) | v14>>8 + v9 += v14 + v4 ^= v9 + v4 = v4<<(32-7) | v4>>7 + v1 += m[14] ^ cst9 + v1 += v6 + v12 ^= v1 + v12 = v12<<(32-8) | v12>>8 + v11 += v12 + v6 ^= v11 + v6 = v6<<(32-7) | v6>>7 + v0 += m[11] ^ cst15 + v0 += v5 + v15 ^= v0 + v15 = v15<<(32-8) | v15>>8 + v10 += v15 + v5 ^= v10 + v5 = v5<<(32-7) | v5>>7 + + // Round 11. + v0 += m[0] ^ cst1 + v0 += v4 + v12 ^= v0 + v12 = v12<<(32-16) | v12>>16 + v8 += v12 + v4 ^= v8 + v4 = v4<<(32-12) | v4>>12 + v1 += m[2] ^ cst3 + v1 += v5 + v13 ^= v1 + v13 = v13<<(32-16) | v13>>16 + v9 += v13 + v5 ^= v9 + v5 = v5<<(32-12) | v5>>12 + v2 += m[4] ^ cst5 + v2 += v6 + v14 ^= v2 + v14 = v14<<(32-16) | v14>>16 + v10 += v14 + v6 ^= v10 + v6 = v6<<(32-12) | v6>>12 + v3 += m[6] ^ cst7 + v3 += v7 + v15 ^= v3 + v15 = v15<<(32-16) | v15>>16 + v11 += v15 + v7 ^= v11 + v7 = v7<<(32-12) | v7>>12 + v2 += m[5] ^ cst4 + v2 += v6 + v14 ^= v2 + v14 = v14<<(32-8) | v14>>8 + v10 += v14 + v6 ^= v10 + v6 = v6<<(32-7) | v6>>7 + v3 += m[7] ^ cst6 + v3 += v7 + v15 ^= v3 + v15 = v15<<(32-8) | v15>>8 + v11 += v15 + v7 ^= v11 + v7 = v7<<(32-7) | v7>>7 + v1 += m[3] ^ cst2 + v1 += v5 + v13 ^= v1 + v13 = v13<<(32-8) | v13>>8 + v9 += v13 + v5 ^= v9 + v5 = v5<<(32-7) | v5>>7 + v0 += m[1] ^ cst0 + v0 += v4 + v12 ^= v0 + v12 = v12<<(32-8) | v12>>8 + v8 += v12 + v4 ^= v8 + v4 = v4<<(32-7) | v4>>7 + v0 += m[8] ^ cst9 + v0 += v5 + v15 ^= v0 + v15 = v15<<(32-16) | v15>>16 + v10 += v15 + v5 ^= v10 + v5 = v5<<(32-12) | v5>>12 + v1 += m[10] ^ cst11 + v1 += v6 + v12 ^= v1 + v12 = v12<<(32-16) | v12>>16 + v11 += v12 + v6 ^= v11 + v6 = v6<<(32-12) | v6>>12 + v2 += m[12] ^ cst13 + v2 += v7 + v13 ^= v2 + v13 = v13<<(32-16) | v13>>16 + v8 += v13 + v7 ^= v8 + v7 = v7<<(32-12) | v7>>12 + v3 += m[14] ^ cst15 + v3 += v4 + v14 ^= v3 + v14 = v14<<(32-16) | v14>>16 + v9 += v14 + v4 ^= v9 + v4 = v4<<(32-12) | v4>>12 + v2 += m[13] ^ cst12 + v2 += v7 + v13 ^= v2 + v13 = v13<<(32-8) | v13>>8 + v8 += v13 + v7 ^= v8 + v7 = v7<<(32-7) | v7>>7 + v3 += m[15] ^ cst14 + v3 += v4 + v14 ^= v3 + v14 = v14<<(32-8) | v14>>8 + v9 += v14 + v4 ^= v9 + v4 = v4<<(32-7) | v4>>7 + v1 += m[11] ^ cst10 + v1 += v6 + v12 ^= v1 + v12 = v12<<(32-8) | v12>>8 + v11 += v12 + v6 ^= v11 + v6 = v6<<(32-7) | v6>>7 + v0 += m[9] ^ cst8 + v0 += v5 + v15 ^= v0 + v15 = v15<<(32-8) | v15>>8 + v10 += v15 + v5 ^= v10 + v5 = v5<<(32-7) | v5>>7 + + // Round 12. + v0 += m[14] ^ cst10 + v0 += v4 + v12 ^= v0 + v12 = v12<<(32-16) | v12>>16 + v8 += v12 + v4 ^= v8 + v4 = v4<<(32-12) | v4>>12 + v1 += m[4] ^ cst8 + v1 += v5 + v13 ^= v1 + v13 = v13<<(32-16) | v13>>16 + v9 += v13 + v5 ^= v9 + v5 = v5<<(32-12) | v5>>12 + v2 += m[9] ^ cst15 + v2 += v6 + v14 ^= v2 + v14 = v14<<(32-16) | v14>>16 + v10 += v14 + v6 ^= v10 + v6 = v6<<(32-12) | v6>>12 + v3 += m[13] ^ cst6 + v3 += v7 + v15 ^= v3 + v15 = v15<<(32-16) | v15>>16 + v11 += v15 + v7 ^= v11 + v7 = v7<<(32-12) | v7>>12 + v2 += m[15] ^ cst9 + v2 += v6 + v14 ^= v2 + v14 = v14<<(32-8) | v14>>8 + v10 += v14 + v6 ^= v10 + v6 = v6<<(32-7) | v6>>7 + v3 += m[6] ^ cst13 + v3 += v7 + v15 ^= v3 + v15 = v15<<(32-8) | v15>>8 + v11 += v15 + v7 ^= v11 + v7 = v7<<(32-7) | v7>>7 + v1 += m[8] ^ cst4 + v1 += v5 + v13 ^= v1 + v13 = v13<<(32-8) | v13>>8 + v9 += v13 + v5 ^= v9 + v5 = v5<<(32-7) | v5>>7 + v0 += m[10] ^ cst14 + v0 += v4 + v12 ^= v0 + v12 = v12<<(32-8) | v12>>8 + v8 += v12 + v4 ^= v8 + v4 = v4<<(32-7) | v4>>7 + v0 += m[1] ^ cst12 + v0 += v5 + v15 ^= v0 + v15 = v15<<(32-16) | v15>>16 + v10 += v15 + v5 ^= v10 + v5 = v5<<(32-12) | v5>>12 + v1 += m[0] ^ cst2 + v1 += v6 + v12 ^= v1 + v12 = v12<<(32-16) | v12>>16 + v11 += v12 + v6 ^= v11 + v6 = v6<<(32-12) | v6>>12 + v2 += m[11] ^ cst7 + v2 += v7 + v13 ^= v2 + v13 = v13<<(32-16) | v13>>16 + v8 += v13 + v7 ^= v8 + v7 = v7<<(32-12) | v7>>12 + v3 += m[5] ^ cst3 + v3 += v4 + v14 ^= v3 + v14 = v14<<(32-16) | v14>>16 + v9 += v14 + v4 ^= v9 + v4 = v4<<(32-12) | v4>>12 + v2 += m[7] ^ cst11 + v2 += v7 + v13 ^= v2 + v13 = v13<<(32-8) | v13>>8 + v8 += v13 + v7 ^= v8 + v7 = v7<<(32-7) | v7>>7 + v3 += m[3] ^ cst5 + v3 += v4 + v14 ^= v3 + v14 = v14<<(32-8) | v14>>8 + v9 += v14 + v4 ^= v9 + v4 = v4<<(32-7) | v4>>7 + v1 += m[2] ^ cst0 + v1 += v6 + v12 ^= v1 + v12 = v12<<(32-8) | v12>>8 + v11 += v12 + v6 ^= v11 + v6 = v6<<(32-7) | v6>>7 + v0 += m[12] ^ cst1 + v0 += v5 + v15 ^= v0 + v15 = v15<<(32-8) | v15>>8 + v10 += v15 + v5 ^= v10 + v5 = v5<<(32-7) | v5>>7 + + // Round 13. + v0 += m[11] ^ cst8 + v0 += v4 + v12 ^= v0 + v12 = v12<<(32-16) | v12>>16 + v8 += v12 + v4 ^= v8 + v4 = v4<<(32-12) | v4>>12 + v1 += m[12] ^ cst0 + v1 += v5 + v13 ^= v1 + v13 = v13<<(32-16) | v13>>16 + v9 += v13 + v5 ^= v9 + v5 = v5<<(32-12) | v5>>12 + v2 += m[5] ^ cst2 + v2 += v6 + v14 ^= v2 + v14 = v14<<(32-16) | v14>>16 + v10 += v14 + v6 ^= v10 + v6 = v6<<(32-12) | v6>>12 + v3 += m[15] ^ cst13 + v3 += v7 + v15 ^= v3 + v15 = v15<<(32-16) | v15>>16 + v11 += v15 + v7 ^= v11 + v7 = v7<<(32-12) | v7>>12 + v2 += m[2] ^ cst5 + v2 += v6 + v14 ^= v2 + v14 = v14<<(32-8) | v14>>8 + v10 += v14 + v6 ^= v10 + v6 = v6<<(32-7) | v6>>7 + v3 += m[13] ^ cst15 + v3 += v7 + v15 ^= v3 + v15 = v15<<(32-8) | v15>>8 + v11 += v15 + v7 ^= v11 + v7 = v7<<(32-7) | v7>>7 + v1 += m[0] ^ cst12 + v1 += v5 + v13 ^= v1 + v13 = v13<<(32-8) | v13>>8 + v9 += v13 + v5 ^= v9 + v5 = v5<<(32-7) | v5>>7 + v0 += m[8] ^ cst11 + v0 += v4 + v12 ^= v0 + v12 = v12<<(32-8) | v12>>8 + v8 += v12 + v4 ^= v8 + v4 = v4<<(32-7) | v4>>7 + v0 += m[10] ^ cst14 + v0 += v5 + v15 ^= v0 + v15 = v15<<(32-16) | v15>>16 + v10 += v15 + v5 ^= v10 + v5 = v5<<(32-12) | v5>>12 + v1 += m[3] ^ cst6 + v1 += v6 + v12 ^= v1 + v12 = v12<<(32-16) | v12>>16 + v11 += v12 + v6 ^= v11 + v6 = v6<<(32-12) | v6>>12 + v2 += m[7] ^ cst1 + v2 += v7 + v13 ^= v2 + v13 = v13<<(32-16) | v13>>16 + v8 += v13 + v7 ^= v8 + v7 = v7<<(32-12) | v7>>12 + v3 += m[9] ^ cst4 + v3 += v4 + v14 ^= v3 + v14 = v14<<(32-16) | v14>>16 + v9 += v14 + v4 ^= v9 + v4 = v4<<(32-12) | v4>>12 + v2 += m[1] ^ cst7 + v2 += v7 + v13 ^= v2 + v13 = v13<<(32-8) | v13>>8 + v8 += v13 + v7 ^= v8 + v7 = v7<<(32-7) | v7>>7 + v3 += m[4] ^ cst9 + v3 += v4 + v14 ^= v3 + v14 = v14<<(32-8) | v14>>8 + v9 += v14 + v4 ^= v9 + v4 = v4<<(32-7) | v4>>7 + v1 += m[6] ^ cst3 + v1 += v6 + v12 ^= v1 + v12 = v12<<(32-8) | v12>>8 + v11 += v12 + v6 ^= v11 + v6 = v6<<(32-7) | v6>>7 + v0 += m[14] ^ cst10 + v0 += v5 + v15 ^= v0 + v15 = v15<<(32-8) | v15>>8 + v10 += v15 + v5 ^= v10 + v5 = v5<<(32-7) | v5>>7 + + // Round 14. + v0 += m[7] ^ cst9 + v0 += v4 + v12 ^= v0 + v12 = v12<<(32-16) | v12>>16 + v8 += v12 + v4 ^= v8 + v4 = v4<<(32-12) | v4>>12 + v1 += m[3] ^ cst1 + v1 += v5 + v13 ^= v1 + v13 = v13<<(32-16) | v13>>16 + v9 += v13 + v5 ^= v9 + v5 = v5<<(32-12) | v5>>12 + v2 += m[13] ^ cst12 + v2 += v6 + v14 ^= v2 + v14 = v14<<(32-16) | v14>>16 + v10 += v14 + v6 ^= v10 + v6 = v6<<(32-12) | v6>>12 + v3 += m[11] ^ cst14 + v3 += v7 + v15 ^= v3 + v15 = v15<<(32-16) | v15>>16 + v11 += v15 + v7 ^= v11 + v7 = v7<<(32-12) | v7>>12 + v2 += m[12] ^ cst13 + v2 += v6 + v14 ^= v2 + v14 = v14<<(32-8) | v14>>8 + v10 += v14 + v6 ^= v10 + v6 = v6<<(32-7) | v6>>7 + v3 += m[14] ^ cst11 + v3 += v7 + v15 ^= v3 + v15 = v15<<(32-8) | v15>>8 + v11 += v15 + v7 ^= v11 + v7 = v7<<(32-7) | v7>>7 + v1 += m[1] ^ cst3 + v1 += v5 + v13 ^= v1 + v13 = v13<<(32-8) | v13>>8 + v9 += v13 + v5 ^= v9 + v5 = v5<<(32-7) | v5>>7 + v0 += m[9] ^ cst7 + v0 += v4 + v12 ^= v0 + v12 = v12<<(32-8) | v12>>8 + v8 += v12 + v4 ^= v8 + v4 = v4<<(32-7) | v4>>7 + v0 += m[2] ^ cst6 + v0 += v5 + v15 ^= v0 + v15 = v15<<(32-16) | v15>>16 + v10 += v15 + v5 ^= v10 + v5 = v5<<(32-12) | v5>>12 + v1 += m[5] ^ cst10 + v1 += v6 + v12 ^= v1 + v12 = v12<<(32-16) | v12>>16 + v11 += v12 + v6 ^= v11 + v6 = v6<<(32-12) | v6>>12 + v2 += m[4] ^ cst0 + v2 += v7 + v13 ^= v2 + v13 = v13<<(32-16) | v13>>16 + v8 += v13 + v7 ^= v8 + v7 = v7<<(32-12) | v7>>12 + v3 += m[15] ^ cst8 + v3 += v4 + v14 ^= v3 + v14 = v14<<(32-16) | v14>>16 + v9 += v14 + v4 ^= v9 + v4 = v4<<(32-12) | v4>>12 + v2 += m[0] ^ cst4 + v2 += v7 + v13 ^= v2 + v13 = v13<<(32-8) | v13>>8 + v8 += v13 + v7 ^= v8 + v7 = v7<<(32-7) | v7>>7 + v3 += m[8] ^ cst15 + v3 += v4 + v14 ^= v3 + v14 = v14<<(32-8) | v14>>8 + v9 += v14 + v4 ^= v9 + v4 = v4<<(32-7) | v4>>7 + v1 += m[10] ^ cst5 + v1 += v6 + v12 ^= v1 + v12 = v12<<(32-8) | v12>>8 + v11 += v12 + v6 ^= v11 + v6 = v6<<(32-7) | v6>>7 + v0 += m[6] ^ cst2 + v0 += v5 + v15 ^= v0 + v15 = v15<<(32-8) | v15>>8 + v10 += v15 + v5 ^= v10 + v5 = v5<<(32-7) | v5>>7 + + h0 ^= v0 ^ v8 ^ s0 + h1 ^= v1 ^ v9 ^ s1 + h2 ^= v2 ^ v10 ^ s2 + h3 ^= v3 ^ v11 ^ s3 + h4 ^= v4 ^ v12 ^ s0 + h5 ^= v5 ^ v13 ^ s1 + h6 ^= v6 ^ v14 ^ s2 + h7 ^= v7 ^ v15 ^ s3 + + p = p[BlockSize:] + } + d.h[0], d.h[1], d.h[2], d.h[3], d.h[4], d.h[5], d.h[6], d.h[7] = h0, h1, h2, h3, h4, h5, h6, h7 +} diff --git a/contrib/backends/nntpchand/src/vendor/github.com/dchest/blake2b/README b/contrib/backends/nntpchand/src/vendor/github.com/dchest/blake2b/README new file mode 100644 index 0000000..09f0143 --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/dchest/blake2b/README @@ -0,0 +1,23 @@ +Go implementation of BLAKE2b collision-resistant cryptographic hash function +created by Jean-Philippe Aumasson, Samuel Neves, Zooko Wilcox-O'Hearn, and +Christian Winnerlein (https://blake2.net). + +INSTALLATION + + $ go get github.com/dchest/blake2b + + +DOCUMENTATION + + See http://godoc.org/github.com/dchest/blake2b + + +PUBLIC DOMAIN DEDICATION + +Written in 2012 by Dmitry Chestnykh. + +To the extent possible under law, the author have dedicated all copyright +and related and neighboring rights to this software to the public domain +worldwide. This software is distributed without any warranty. +http://creativecommons.org/publicdomain/zero/1.0/ + diff --git a/contrib/backends/nntpchand/src/vendor/github.com/dchest/blake2b/blake2b.go b/contrib/backends/nntpchand/src/vendor/github.com/dchest/blake2b/blake2b.go new file mode 100644 index 0000000..c7afe4f --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/dchest/blake2b/blake2b.go @@ -0,0 +1,293 @@ +// Written in 2012 by Dmitry Chestnykh. +// +// To the extent possible under law, the author have dedicated all copyright +// and related and neighboring rights to this software to the public domain +// worldwide. This software is distributed without any warranty. +// http://creativecommons.org/publicdomain/zero/1.0/ + +// Package blake2b implements BLAKE2b cryptographic hash function. +package blake2b + +import ( + "encoding/binary" + "errors" + "hash" +) + +const ( + BlockSize = 128 // block size of algorithm + Size = 64 // maximum digest size + SaltSize = 16 // maximum salt size + PersonSize = 16 // maximum personalization string size + KeySize = 64 // maximum size of key +) + +type digest struct { + h [8]uint64 // current chain value + t [2]uint64 // message bytes counter + f [2]uint64 // finalization flags + x [BlockSize]byte // buffer for data not yet compressed + nx int // number of bytes in buffer + + ih [8]uint64 // initial chain value (after config) + paddedKey [BlockSize]byte // copy of key, padded with zeros + isKeyed bool // indicates whether hash was keyed + size uint8 // digest size in bytes + isLastNode bool // indicates processing of the last node in tree hashing +} + +// Initialization values. +var iv = [8]uint64{ + 0x6a09e667f3bcc908, 0xbb67ae8584caa73b, + 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1, + 0x510e527fade682d1, 0x9b05688c2b3e6c1f, + 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179, +} + +// Config is used to configure hash function parameters and keying. +// All parameters are optional. +type Config struct { + Size uint8 // digest size (if zero, default size of 64 bytes is used) + Key []byte // key for prefix-MAC + Salt []byte // salt (if < 16 bytes, padded with zeros) + Person []byte // personalization (if < 16 bytes, padded with zeros) + Tree *Tree // parameters for tree hashing +} + +// Tree represents parameters for tree hashing. +type Tree struct { + Fanout uint8 // fanout + MaxDepth uint8 // maximal depth + LeafSize uint32 // leaf maximal byte length (0 for unlimited) + NodeOffset uint64 // node offset (0 for first, leftmost or leaf) + NodeDepth uint8 // node depth (0 for leaves) + InnerHashSize uint8 // inner hash byte length + IsLastNode bool // indicates processing of the last node of layer +} + +var ( + defaultConfig = &Config{Size: Size} + config256 = &Config{Size: 32} +) + +func verifyConfig(c *Config) error { + if c.Size > Size { + return errors.New("digest size is too large") + } + if len(c.Key) > KeySize { + return errors.New("key is too large") + } + if len(c.Salt) > SaltSize { + // Smaller salt is okay: it will be padded with zeros. + return errors.New("salt is too large") + } + if len(c.Person) > PersonSize { + // Smaller personalization is okay: it will be padded with zeros. + return errors.New("personalization is too large") + } + if c.Tree != nil { + if c.Tree.InnerHashSize > Size { + return errors.New("incorrect tree inner hash size") + } + } + return nil +} + +// New returns a new hash.Hash configured with the given Config. +// Config can be nil, in which case the default one is used, calculating 64-byte digest. +// Returns non-nil error if Config contains invalid parameters. +func New(c *Config) (hash.Hash, error) { + if c == nil { + c = defaultConfig + } else { + if c.Size == 0 { + // Set default size if it's zero. + c.Size = Size + } + if err := verifyConfig(c); err != nil { + return nil, err + } + } + d := new(digest) + d.initialize(c) + return d, nil +} + +// initialize initializes digest with the given +// config, which must be non-nil and verified. +func (d *digest) initialize(c *Config) { + // Create parameter block. + var p [BlockSize]byte + p[0] = c.Size + p[1] = uint8(len(c.Key)) + if c.Salt != nil { + copy(p[32:], c.Salt) + } + if c.Person != nil { + copy(p[48:], c.Person) + } + if c.Tree != nil { + p[2] = c.Tree.Fanout + p[3] = c.Tree.MaxDepth + binary.LittleEndian.PutUint32(p[4:], c.Tree.LeafSize) + binary.LittleEndian.PutUint64(p[8:], c.Tree.NodeOffset) + p[16] = c.Tree.NodeDepth + p[17] = c.Tree.InnerHashSize + } else { + p[2] = 1 + p[3] = 1 + } + // Initialize. + d.size = c.Size + for i := 0; i < 8; i++ { + d.h[i] = iv[i] ^ binary.LittleEndian.Uint64(p[i*8:]) + } + if c.Tree != nil && c.Tree.IsLastNode { + d.isLastNode = true + } + // Process key. + if len(c.Key) > 0 { + copy(d.paddedKey[:], c.Key) + d.Write(d.paddedKey[:]) + d.isKeyed = true + } + // Save a copy of initialized state. + copy(d.ih[:], d.h[:]) +} + +// New512 returns a new hash.Hash computing the BLAKE2b 64-byte checksum. +func New512() hash.Hash { + d := new(digest) + d.initialize(defaultConfig) + return d +} + +// New256 returns a new hash.Hash computing the BLAKE2b 32-byte checksum. +func New256() hash.Hash { + d := new(digest) + d.initialize(config256) + return d +} + +// NewMAC returns a new hash.Hash computing BLAKE2b prefix- +// Message Authentication Code of the given size in bytes +// (up to 64) with the given key (up to 64 bytes in length). +func NewMAC(outBytes uint8, key []byte) hash.Hash { + d, err := New(&Config{Size: outBytes, Key: key}) + if err != nil { + panic(err.Error()) + } + return d +} + +// Reset resets the state of digest to the initial state +// after configuration and keying. +func (d *digest) Reset() { + copy(d.h[:], d.ih[:]) + d.t[0] = 0 + d.t[1] = 0 + d.f[0] = 0 + d.f[1] = 0 + d.nx = 0 + if d.isKeyed { + d.Write(d.paddedKey[:]) + } +} + +// Size returns the digest size in bytes. +func (d *digest) Size() int { return int(d.size) } + +// BlockSize returns the algorithm block size in bytes. +func (d *digest) BlockSize() int { return BlockSize } + +func (d *digest) Write(p []byte) (nn int, err error) { + nn = len(p) + left := BlockSize - d.nx + if len(p) > left { + // Process buffer. + copy(d.x[d.nx:], p[:left]) + p = p[left:] + blocks(d, d.x[:]) + d.nx = 0 + } + // Process full blocks except for the last one. + if len(p) > BlockSize { + n := len(p) &^ (BlockSize - 1) + if n == len(p) { + n -= BlockSize + } + blocks(d, p[:n]) + p = p[n:] + } + // Fill buffer. + d.nx += copy(d.x[d.nx:], p) + return +} + +// Sum returns the calculated checksum. +func (d0 *digest) Sum(in []byte) []byte { + // Make a copy of d0 so that caller can keep writing and summing. + d := *d0 + hash := d.checkSum() + return append(in, hash[:d.size]...) +} + +func (d *digest) checkSum() [Size]byte { + // Do not create unnecessary copies of the key. + if d.isKeyed { + for i := 0; i < len(d.paddedKey); i++ { + d.paddedKey[i] = 0 + } + } + + dec := BlockSize - uint64(d.nx) + if d.t[0] < dec { + d.t[1]-- + } + d.t[0] -= dec + + // Pad buffer with zeros. + for i := d.nx; i < len(d.x); i++ { + d.x[i] = 0 + } + // Set last block flag. + d.f[0] = 0xffffffffffffffff + if d.isLastNode { + d.f[1] = 0xffffffffffffffff + } + // Compress last block. + blocks(d, d.x[:]) + + var out [Size]byte + j := 0 + for _, s := range d.h[:(d.size-1)/8+1] { + out[j+0] = byte(s >> 0) + out[j+1] = byte(s >> 8) + out[j+2] = byte(s >> 16) + out[j+3] = byte(s >> 24) + out[j+4] = byte(s >> 32) + out[j+5] = byte(s >> 40) + out[j+6] = byte(s >> 48) + out[j+7] = byte(s >> 56) + j += 8 + } + return out +} + +// Sum512 returns a 64-byte BLAKE2b hash of data. +func Sum512(data []byte) [64]byte { + var d digest + d.initialize(defaultConfig) + d.Write(data) + return d.checkSum() +} + +// Sum256 returns a 32-byte BLAKE2b hash of data. +func Sum256(data []byte) (out [32]byte) { + var d digest + d.initialize(config256) + d.Write(data) + sum := d.checkSum() + copy(out[:], sum[:32]) + return +} diff --git a/contrib/backends/nntpchand/src/vendor/github.com/dchest/blake2b/blake2b_test.go b/contrib/backends/nntpchand/src/vendor/github.com/dchest/blake2b/blake2b_test.go new file mode 100644 index 0000000..38e4c28 --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/dchest/blake2b/blake2b_test.go @@ -0,0 +1,625 @@ +// Written in 2012 by Dmitry Chestnykh. +// +// To the extent possible under law, the author have dedicated all copyright +// and related and neighboring rights to this software to the public domain +// worldwide. This software is distributed without any warranty. +// http://creativecommons.org/publicdomain/zero/1.0/ + +package blake2b + +import ( + "fmt" + "testing" +) + +func TestSum(t *testing.T) { + buf := make([]byte, len(golden)) + for i := range buf { + buf[i] = byte(i) + } + h := New512() + for i, v := range golden { + if v != fmt.Sprintf("%x", Sum512(buf[:i])) { + t.Errorf("%d: Sum512(): \nexpected %s\ngot %x", i, v, Sum512(buf[:i])) + } + h.Reset() + h.Write(buf[:i]) + sum := h.Sum(nil) + if fmt.Sprintf("%x", sum) != v { + t.Errorf("%d:\nexpected %s\ngot %x", i, v, sum) + } + + } +} + +func TestSum256(t *testing.T) { + // Simple one-hash test. + in := "The cryptographic hash function BLAKE2 is an improved version of the SHA-3 finalist BLAKE" + good := "e5866d0c42b4e27e89a316fa5c3ba8cacae754e53d8267da37ba1893c2fcd92c" + if good != fmt.Sprintf("%x", Sum256([]byte(in))) { + t.Errorf("Sum256(): \nexpected %s\ngot %x", good, Sum256([]byte(in))) + } + +} + +func TestSumLength(t *testing.T) { + h, _ := New(&Config{Size: 19}) + sum := h.Sum(nil) + if len(sum) != 19 { + t.Fatalf("Sum() returned a slice larger than the given hash size") + } +} + +func TestKeyedSum(t *testing.T) { + buf := make([]byte, len(goldenKeyed)) + for i := range buf { + buf[i] = byte(i) + } + h := NewMAC(64, buf[:64]) + for i, v := range goldenKeyed { + h.Reset() + h.Write(buf[:i]) + sum := h.Sum(nil) + if fmt.Sprintf("%x", sum) != v { + t.Errorf("%d:\nexpected %s\ngot %x", i, v, sum) + } + + } +} + +var bench = New512() +var buf = make([]byte, 8<<10) + +func BenchmarkWrite1K(b *testing.B) { + b.SetBytes(1024) + for i := 0; i < b.N; i++ { + bench.Write(buf[:1024]) + } +} + +func BenchmarkWrite8K(b *testing.B) { + b.SetBytes(int64(len(buf))) + for i := 0; i < b.N; i++ { + bench.Write(buf) + } +} + +func BenchmarkHash64(b *testing.B) { + b.SetBytes(64) + for i := 0; i < b.N; i++ { + Sum512(buf[:64]) + } +} + +func BenchmarkHash128(b *testing.B) { + b.SetBytes(128) + for i := 0; i < b.N; i++ { + Sum512(buf[:128]) + } +} + +func BenchmarkHash1K(b *testing.B) { + b.SetBytes(1024) + for i := 0; i < b.N; i++ { + Sum512(buf[:1024]) + } +} + +// Test vectors taken from reference implementation in C#. +var golden = []string{ + "786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce", + "2fa3f686df876995167e7c2e5d74c4c7b6e48f8068fe0e44208344d480f7904c36963e44115fe3eb2a3ac8694c28bcb4f5a0f3276f2e79487d8219057a506e4b", + "1c08798dc641aba9dee435e22519a4729a09b2bfe0ff00ef2dcd8ed6f8a07d15eaf4aee52bbf18ab5608a6190f70b90486c8a7d4873710b1115d3debbb4327b5", + "40a374727302d9a4769c17b5f409ff32f58aa24ff122d7603e4fda1509e919d4107a52c57570a6d94e50967aea573b11f86f473f537565c66f7039830a85d186", + "77ddf4b14425eb3d053c1e84e3469d92c4cd910ed20f92035e0c99d8a7a86cecaf69f9663c20a7aa230bc82f60d22fb4a00b09d3eb8fc65ef547fe63c8d3ddce", + "cbaa0ba7d482b1f301109ae41051991a3289bc1198005af226c5e4f103b66579f461361044c8ba3439ff12c515fb29c52161b7eb9c2837b76a5dc33f7cb2e2e8", + "f95d45cf69af5c2023bdb505821e62e85d7caedf7beda12c0248775b0c88205eeb35af3a90816f6608ce7dd44ec28db1140614e1ddebf3aa9cd1843e0fad2c36", + "8f945ba700f2530e5c2a7df7d5dce0f83f9efc78c073fe71ae1f88204a4fd1cf70a073f5d1f942ed623aa16e90a871246c90c45b621b3401a5ddbd9df6264165", + "e998e0dc03ec30eb99bb6bfaaf6618acc620320d7220b3af2b23d112d8e9cb1262f3c0d60d183b1ee7f096d12dae42c958418600214d04f5ed6f5e718be35566", + "6a9a090c61b3410aede7ec9138146ceb2c69662f460c3da53c6515c1eb31f41ca3d280e567882f95cf664a94147d78f42cfc714a40d22ef19470e053493508a2", + "29102511d749db3cc9b4e335fa1f5e8faca8421d558f6a3f3321d50d044a248ba595cfc3efd3d2adc97334da732413f5cbf4751c362ba1d53862ac1e8dabeee8", + "c97a4779d47e6f77729b5917d0138abb35980ab641bd73a8859eb1ac98c05362ed7d608f2e9587d6ba9e271d343125d40d933a8ed04ec1fe75ec407c7a53c34e", + "10f0dc91b9f845fb95fad6860e6ce1adfa002c7fc327116d44d047cd7d5870d772bb12b5fac00e02b08ac2a0174d0446c36ab35f14ca31894cd61c78c849b48a", + "dea9101cac62b8f6a3c650f90eea5bfae2653a4eafd63a6d1f0f132db9e4f2b1b662432ec85b17bcac41e775637881f6aab38dd66dcbd080f0990a7a6e9854fe", + "441ffaa08cd79dff4afc9b9e5b5620eec086730c25f661b1d6fbfbd1cec3148dd72258c65641f2fca5eb155fadbcabb13c6e21dc11faf72c2a281b7d56145f19", + "444b240fe3ed86d0e2ef4ce7d851edde22155582aa0914797b726cd058b6f45932e0e129516876527b1dd88fc66d7119f4ab3bed93a61a0e2d2d2aeac336d958", + "bfbabbef45554ccfa0dc83752a19cc35d5920956b301d558d772282bc867009168e9e98606bb5ba73a385de5749228c925a85019b71f72fe29b3cd37ca52efe6", + "9c4d0c3e1cdbbf485bec86f41cec7c98373f0e09f392849aaa229ebfbf397b22085529cb7ef39f9c7c2222a514182b1effaa178cc3687b1b2b6cbcb6fdeb96f8", + "477176b3bfcbadd7657c23c24625e4d0d674d1868f006006398af97aa41877c8e70d3d14c3bbc9bbcdcea801bd0e1599af1f3eec67405170f4e26c964a57a8b7", + "a78c490eda3173bb3f10dee52f110fb1c08e0302230b85ddd7c11257d92de148785ef00c039c0bb8eb9808a35b2d8c080f572859714c9d4069c5bcaf090e898e", + "58d023397beb5b4145cb2255b07d74290b36d9fd1e594afbd8eea47c205b2efbfe6f46190faf95af504ab072e36f6c85d767a321bfd7f22687a4abbf494a689c", + "4001ec74d5a46fd29c2c3cdbe5d1b9f20e51a941be98d2a4e1e2fbf866a672121db6f81a514cfd10e7358d571bdba48e4ce708b9d124894bc0b5ed554935f73a", + "ccd1b22dab6511225d2401ea2d8625d206a12473cc732b615e5640cefff0a4adf971b0e827a619e0a80f5db9ccd0962329010d07e34a2064e731c520817b2183", + "b4a0a9e3574edb9e1e72aa31e39cc5f30dbf943f8cabc408449654a39131e66d718a18819143e3ea96b4a1895988a1c0056cf2b6e04f9ac19d657383c2910c44", + "447becab16630608d39f4f058b16f7af95b85a76aa0fa7cea2b80755fb76e9c804f2ca78f02643c915fbf2fce5e19de86000de03b18861815a83126071f8a37b", + "54e6dab9977380a5665822db93374eda528d9beb626f9b94027071cb26675e112b4a7fec941ee60a81e4d2ea3ff7bc52cfc45dfbfe735a1c646b2cf6d6a49b62", + "3ea62625949e3646704d7e3c906f82f6c028f540f5f72a794b0c57bf97b7649bfeb90b01d3ca3e829de21b3826e6f87014d3c77350cb5a15ff5d468a81bec160", + "213cfe145c54a33691569980e5938c8883a46d84d149c8ff1a67cd287b4d49c6da69d3a035443db085983d0efe63706bd5b6f15a7da459e8d50a19093db55e80", + "5716c4a38f38db104e494a0a27cbe89a26a6bb6f499ec01c8c01aa7cb88497e75148cd6eee12a7168b6f78ab74e4be749251a1a74c38c86d6129177e2889e0b6", + "030460a98bdf9ff17cd96404f28fc304f2b7c04eaade53677fd28f788ca22186b8bc80dd21d17f8549c711aff0e514e19d4e15f5990252a03e082f28dc2052f6", + "19e7f1ccee88a10672333e390cf22013a8c734c6cb9eab41f17c3c8032a2e4aca0569ea36f0860c7a1af28fa476840d66011168859334a9e4ef9cc2e61a0e29e", + "29f8b8c78c80f2fcb4bdf7825ed90a70d625ff785d262677e250c04f3720c888d03f8045e4edf3f5285bd39d928a10a7d0a5df00b8484ac2868142a1e8bea351", + "5c52920a7263e39d57920ca0cb752ac6d79a04fef8a7a216a1ecb7115ce06d89fd7d735bd6f4272555dba22c2d1c96e6352322c62c5630fde0f4777a76c3de2c", + "83b098f262251bf660064a9d3511ce7687a09e6dfbb878299c30e93dfb43a9314db9a600337db26ebeedaf2256a96dabe9b29e7573ad11c3523d874dde5be7ed", + "9447d98aa5c9331352f43d3e56d0a9a9f9581865998e2885cc56dd0a0bd5a7b50595bd10f7529bcd31f37dc16a1465d594079667da2a3fcb70401498837cedeb", + "867732f2feeb23893097561ac710a4bff453be9cfbedba8ba324f9d312a82d732e1b83b829fdcd177b882ca0c1bf544b223be529924a246a63cf059bfdc50a1b", + "f15ab26d4cdfcf56e196bb6ba170a8fccc414de9285afd98a3d3cf2fb88fcbc0f19832ac433a5b2cc2392a4ce34332987d8d2c2bef6c3466138db0c6e42fa47b", + "2813516d68ed4a08b39d648aa6aacd81e9d655ecd5f0c13556c60fdf0d333ea38464b36c02baccd746e9575e96c63014f074ae34a0a25b320f0fbedd6acf7665", + "d3259afca8a48962fa892e145acf547f26923ae8d4924c8a531581526b04b44c7af83c643ef5a0bc282d36f3fb04c84e28b351f40c74b69dc7840bc717b6f15f", + "f14b061ae359fa31b989e30332bfe8de8cc8cdb568e14be214a2223b84caab7419549ecfcc96ce2acec119485d87d157d3a8734fc426597d64f36570ceaf224d", + "55e70b01d1fbf8b23b57fb62e26c2ce54f13f8fa2464e6eb98d16a6117026d8b90819012496d4071ebe2e59557ece3519a7aa45802f9615374877332b73490b3", + "25261eb296971d6e4a71b2928e64839c67d422872bf9f3c31993615222de9f8f0b2c4be8548559b4b354e736416e3218d4e8a1e219a4a6d43e1a9a521d0e75fc", + "08307f347c41294e34bb54cb42b1522d22f824f7b6e5db50fda096798e181a8f026fa27b4ae45d52a62caf9d5198e24a4913c6671775b2d723c1239bfbf016d7", + "1e5c62e7e9bfa1b118747a2de08b3ca10112af96a46e4b22c3fc06f9bfee4eb5c49e057a4a4886234324572576bb9b5ecfde0d99b0de4f98ec16e4d1b85fa947", + "c74a77395fb8bc126447454838e561e962853dc7eb49a1e3cb67c3d0851f3e39517be8c350ac910903d49cd2bfdf545c99316d0346170b739f0add5d533c2cfc", + "0dd57b423cc01eb2861391eb886a0d17079b933fc76eb3fc08a19f8a74952cb68f6bcdc644f77370966e4d13e80560bcf082ef0479d48fbbab4df03b53a4e178", + "4d8dc3923edccdfce70072398b8a3da5c31fcb3ee3b645c85f717cbaeb4b673a19394425a585bfb464d92f1597d0b754d163f97ced343b25db5a70ef48ebb34f", + "f0a50553e4dfb0c4e3e3d3ba82034857e3b1e50918f5b8a7d698e10d242b0fb544af6c92d0c3aaf9932220416117b4e78ecb8a8f430e13b82a5915290a5819c5", + "b15543f3f736086627cc5365e7e8988c2ef155c0fd4f428961b00d1526f04d6d6a658b4b8ed32c5d8621e7f4f8e8a933d9ecc9dd1b8333cbe28cfc37d9719e1c", + "7b4fa158e415fef023247264cbbe15d16d91a44424a8db707eb1e2033c30e9e1e7c8c0864595d2cb8c580eb47e9d16abbd7e44e824f7cedb7def57130e52cfe9", + "60424ff23234c34dc9687ad502869372cc31a59380186bc2361c835d972f49666eb1ac69629de646f03f9b4db9e2ace093fbfdf8f20ab5f98541978be8ef549f", + "7406018ce704d84f5eb9c79fea97da345699468a350ee0b2d0f3a4bf2070304ea862d72a51c57d3064947286f531e0eaf7563702262e6c724abf5ed8c8398d17", + "14ef5c6d647b3bd1e6e32006c231199810de5c4dc88e70240273b0ea18e651a3eb4f5ca3114b8a56716969c7cda27e0c8db832ad5e89a2dc6cb0adbe7d93abd1", + "38cf6c24e3e08bcf1f6cf3d1b1f65b905239a3118033249e448113ec632ea6dc346feeb2571c38bd9a7398b2221280328002b23e1a45adaffe66d93f6564eaa2", + "6cd7208a4bc7e7e56201bbba02a0f489cd384abe40afd4222f158b3d986ee72a54c50fb64fd4ed2530eda2c8af2928a0da6d4f830ae1c9db469dfd970f12a56f", + "659858f0b5c9edab5b94fd732f6e6b17c51cc096104f09beb3afc3aa467c2ecf885c4c6541effa9023d3b5738ae5a14d867e15db06fe1f9d1127b77e1aabb516", + "26cca0126f5d1a813c62e5c71001c046f9c92095704550be5873a495a999ad010a4f79491f24f286500adce1a137bc2084e4949f5b7294cefe51ecaff8e95cba", + "4147c1f55172788c5567c561feef876f621fff1ce87786b8467637e70dfbcd0dbdb6415cb600954ab9c04c0e457e625b407222c0fe1ae21b2143688ada94dc58", + "5b1bf154c62a8af6e93d35f18f7f90abb16a6ef0e8d1aecd118bf70167bab2af08935c6fdc0663ce74482d17a8e54b546d1c296631c65f3b522a515839d43d71", + "9f600419a4e8f4fb834c24b0f7fc13bf4e279d98e8a3c765ee934917403e3a66097182ea21453cb63ebbe8b73a9c2167596446438c57627f330badd4f569f7d6", + "457ef6466a8924fd8011a34471a5a1ac8ccd9bd0d07a97414ac943021ce4b9e4b9c8db0a28f016ed43b1542481990022147b313e194671131e708dd43a3ed7dc", + "9997b2194d9af6dfcb9143f41c0ed83d3a3f4388361103d38c2a49b280a581212715fd908d41c651f5c715ca38c0ce2830a37e00e508ced1bcdc320e5e4d1e2e", + "5c6bbf16baa180f986bd40a1287ed4c549770e7284858fc47bc21ab95ebbf3374b4ee3fd9f2af60f3395221b2acc76f2d34c132954049f8a3a996f1e32ec84e5", + "d10bf9a15b1c9fc8d41f89bb140bf0be08d2f3666176d13baac4d381358ad074c9d4748c300520eb026daeaea7c5b158892fde4e8ec17dc998dcd507df26eb63", + "2fc6e69fa26a89a5ed269092cb9b2a449a4409a7a44011eecad13d7c4b0456602d402fa5844f1a7a758136ce3d5d8d0e8b86921ffff4f692dd95bdc8e5ff0052", + "fcbe8be7dcb49a32dbdf239459e26308b84dff1ea480df8d104eeff34b46fae98627b450c2267d48c0946a697c5b59531452ac0484f1c84e3a33d0c339bb2e28", + "a19093a6e3bcf5952f850f2030f69b9606f147f90b8baee3362da71d9f35b44ef9d8f0a7712ba1877fddcd2d8ea8f1e5a773d0b745d4725605983a2de901f803", + "3c2006423f73e268fa59d2920377eb29a4f9a8b462be15983ee3b85ae8a78e992633581a9099893b63db30241c34f643027dc878279af5850d7e2d4a2653073a", + "d0f2f2e3787653f77cce2fa24835785bbd0c433fc779465a115149905a9dd1cb827a628506d457fcf124a0c2aef9ce2d2a0a0f63545570d8667ff9e2eba07334", + "78a9fc048e25c6dcb5de45667de8ffdd3a93711141d594e9fa62a959475da6075ea8f0916e84e45ad911b75467077ee52d2c9aebf4d58f20ce4a3a00458b05d4", + "45813f441769ab6ed37d349ff6e72267d76ae6bb3e3c612ec05c6e02a12af5a37c918b52bf74267c3f6a3f183a8064ff84c07b193d08066789a01accdb6f9340", + "956da1c68d83a7b881e01b9a966c3c0bf27f68606a8b71d457bd016d4c41dd8a380c709a296cb4c6544792920fd788835771a07d4a16fb52ed48050331dc4c8b", + "df186c2dc09caa48e14e942f75de5ac1b7a21e4f9f072a5b371e09e07345b0740c76177b01278808fec025eded9822c122afd1c63e6f0ce2e32631041063145c", + "87475640966a9fdcd6d3a3b5a2cca5c08f0d882b10243c0ec1bf3c6b1c37f2cd3212f19a057864477d5eaf8faed73f2937c768a0af415e84bbce6bd7de23b660", + "c3b573bbe10949a0fbd4ff884c446f2229b76902f9dfdbb8a0353da5c83ca14e8151bbaac82fd1576a009adc6f1935cf26edd4f1fb8da483e6c5cd9d8923adc3", + "b09d8d0bba8a7286e43568f7907550e42036d674e3c8fc34d8ca46f771d6466b70fb605875f6a863c877d12f07063fdc2e90ccd459b1910dcd52d8f10b2b0a15", + "af3a22bf75b21abfb0acd54422ba1b7300a952eff02ebeb65b5c234471a98df32f4f9643ce1904108a168767924280bd76c83f8c82d9a79d9259b195362a2a04", + "bf4ff2221b7e6957a724cd964aa3d5d0d9941f540413752f4699d8101b3e537508bf09f8508b317736ffd265f2847aa7d84bd2d97569c49d632aed9945e5fa5e", + "9c6b6b78199b1bdacb4300e31479fa622a6b5bc80d4678a6078f88a8268cd7206a2799e8d4621a464ef6b43dd8adffe97caf221b22b6b8778b149a822aefbb09", + "890656f09c99d280b5ecb381f56427b813751bc652c7828078b23a4af83b4e3a61fdbac61f89bee84ea6bee760c047f25c6b0a201c69a38fd6fd971af18588bb", + "31a046f7882ffe6f83ce472e9a0701832ec7b3f76fbcfd1df60fe3ea48fde1651254247c3fd95e100f9172731e17fd5297c11f4bb328363ca361624a81af797c", + "27a60b2d00e7a671d47d0aec2a686a0ac04b52f40ab6629028eb7d13f4baa99ac0fe46ee6c814944f2f4b4d20e9378e4847ea44c13178091e277b87ea7a55711", + "8b5ccef194162c1f19d68f91e0b0928f289ec5283720840c2f73d253111238dcfe94af2b59c2c1ca2591901a7bc060e7459b6c47df0f71701a35cc0aa831b5b6", + "57ab6c4b2229aeb3b70476d803cd63812f107ce6da17fed9b17875e8f86c724f49e024cbf3a1b8b119c50357652b81879d2ade2d588b9e4f7cedba0e4644c9ee", + "0190a8dac320a739f322e15731aa140ddaf5bed294d5c82e54fef29f214e18aafaa84f8be99af62950266b8f901f15dd4c5d35516fc35b4cab2e96e4695bbe1c", + "d14d7c4c415eeb0e10b159224bea127ebd84f9591c702a330f5bb7bb7aa44ea39de6ed01f18da7adf40cfb97c5d152c27528824b21e239526af8f36b214e0cfb", + "be28c4be706970488fac7d29c3bd5c4e986085c4c3332f1f3fd30973db614164ba2f31a78875ffdc150325c88327a9443ed04fdfe5be93876d1628560c764a80", + "031da1069e3a2e9c3382e436ffd79df74b1ca6a8adb2deabe676ab45994cbc054f037d2f0eace858d32c14e2d1c8b46077308e3bdc2c1b53172ecf7a8c14e349", + "4665cef8ba4db4d0acb118f2987f0bb09f8f86aa445aa3d5fc9a8b346864787489e8fcecc125d17e9b56e12988eac5ecc7286883db0661b8ff05da2afff30fe4", + "63b7032e5f930cc9939517f9e986816cfbec2be59b9568b13f2ead05bae7777cab620c6659404f7409e4199a3be5f7865aa7cbdf8c4253f7e8219b1bd5f46fea", + "9f09bf093a2b0ff8c2634b49e37f1b2135b447aa9144c9787dbfd92129316c99e88aab8a21fdef2372d1189aec500f95775f1f92bfb45545e4259fb9b7b02d14", + "f9f8493c68088807df7f6a2693d64ea59f03e9e05a223e68524ca32195a4734b654fcea4d2734c866cf95c889fb10c49159be2f5043dc98bb55e02ef7bdcb082", + "3c9a7359ab4febce07b20ac447b06a240b7fe1dae5439c49b60b5819f7812e4c172406c1aac316713cf0dded1038077258e2eff5b33913d9d95caeb4e6c6b970", + "ad6aab8084510e822cfce8625d62cf4de655f4763884c71e80bab9ac9d5318dba4a6033ed29084e65216c031606ca17615dcfe3ba11d26851ae0999ca6e232cf", + "156e9e6261374c9dc884f36e70f0fe1ab9297997b836fa7d170a9c9ebf575b881e7bcea44d6c0248d35597907154828955be19135852f9228815eca024a8adfb", + "4215407633f4cca9b6788be93e6aa3d963c7d6ce4b147247099f46a3acb500a30038cb3e788c3d29f132ad844e80e9e99251f6db96acd8a091cfc770af53847b", + "1c077e279de6548523502b6df800ffdab5e2c3e9442eb838f58c295f3b147cef9d701c41c321283f00c71affa0619310399126295b78dd4d1a74572ef9ed5135", + "f07a555f49fe481cf4cd0a87b71b82e4a95064d06677fdd90a0eb598877ba1c83d4677b393c3a3b6661c421f5b12cb99d20376ba7275c2f3a8f5a9b7821720da", + "b5911b380d20c7b04323e4026b38e200f534259233b581e02c1e3e2d8438d6c66d5a4eb201d5a8b75072c4ec29106334da70bc79521b0ced2cfd533f5ff84f95", + "01f070a09bae911296361f91aa0e8e0d09a7725478536d9d48c5fe1e5e7c3c5b9b9d6eb07796f6da57ae562a7d70e882e37adfde83f0c433c2cd363536bb22c8", + "6f793eb4374a48b0775acaf9adcf8e45e54270c9475f004ad8d5973e2aca52747ff4ed04ae967275b9f9eb0e1ff75fb4f794fa8be9add7a41304868d103fab10", + "965f20f139765fcc4ce4ba3794675863cac24db472cd2b799d035bce3dbea502da7b524865f6b811d8c5828d3a889646fe64a380da1aa7c7044e9f245dced128", + "ec295b5783601244c30e4641e3b45be222c4dce77a58700f53bc8ec52a941690b4d0b087fb6fcb3f39832b9de8f75ec20bd43079811749cdc907edb94157d180", + "61c72f8ccc91dbb54ca6750bc489672de09faedb8fdd4f94ff2320909a303f5d5a98481c0bc1a625419fb4debfbf7f8a53bb07ec3d985e8ea11e72d559940780", + "afd8145b259eefc8d12620c3c5b03e1ed8fd2ccefe0365078c80fd42c1770e28b44948f27e65a1886690110db814397b68e43d80d1ba16dfa358e739c898cfa3", + "552fc7893cf1ce933ada35c0da98844e41545e244c3157a1428d7b4c21f9cd7e4071aed77b7ca9f1c38fba32237412ef21a342742ec8324378f21e507fafdd88", + "467a33fbadf5ebc52596ef86aaaefc6faba8ee651b1ce04de368a03a5a9040ef2835e00adb09abb3fbd2bce818a2413d0b0253b5bda4fc5b2f6f85f3fd5b55f2", + "22eff8e6dd5236f5f57d94ede874d6c9428e8f5d566f17cd6d1848cd752fe13c655cb10fbaaff76872f2bf2da99e15dc624075e1ec2f58a3f64072121838569e", + "9cec6bbf62c4bce4138abae1cbec8dad31950444e90321b1347196834c114b864af3f3cc3508f83751ffb4eda7c84d140734bb4263c3625c00f04f4c8068981b", + "a8b60fa4fc2442f6f1514ad7402626920cc7c2c9f72124b8cba8ee2cb7c4586f658a4410cffcc0ab88343955e094c6af0d20d0c714fb0a988f543f300f58d389", + "8271cc45dfa5e4170e847e8630b952cf9c2aa777d06f26a7585b8381f188dacc7337391cfcc94b053dc4ec29cc17f077870428f1ac23fddda165ef5a3f155f39", + "bf23c0c25c8060e4f6995f1623a3bebecaa96e308680000a8aa3cd56bb1a6da099e10d9231b37f4519b2efd2c24de72f31a5f19535241b4a59fa3c03ceb790e7", + "877fd652c05281009c0a5250e7a3a671f8b18c108817fe4a874de22da8e45db11958a600c5f62e67d36cbf84474cf244a9c2b03a9fb9dc711cd1a2cab6f3fae0", + "29df4d87ea444baf5bcdf5f4e41579e28a67de84149f06c03f110ea84f572a9f676addd04c4878f49c5c00accda441b1a387caceb2e993bb7a10cd8c2d6717e1", + "710dacb166844639cd7b637c274209424e2449dc35d790bbfa4f76177054a36b3b76fac0ca6e61df1e687000678ac0746df75d0a3954897681fd393a155a1bb4", + "c1d5f93b8dea1f2571babccbc01764541a0cda87e444d673c50966ca559c33354b3acb26e5d5781ffb28847a4b4754d77008c62a835835f500dea7c3b58bdae2", + "a41e41271cdab8af4d72b104bfb2ad041ac4df14677da671d85640c4b187f50c2b66513c4619fbd5d5dc4fe65dd37b9042e9848dda556a504caa2b1c6afe4730", + "e7bcbacdc379c43d81ebadcb37781552fc1d753e8cf310d968392d06c91f1d64cc9e90ce1d22c32d277fc6cda433a4d442c762e9eacf2c259f32d64cf9da3a22", + "51755b4ac5456b13218a19c5b9242f57c4a981e4d4ecdce09a3193362b808a579345d4881c2607a56534dd7f21956aff72c2f4173a6e7b6cc2212ba0e3daee1f", + "dcc2c4beb9c1f2607b786c20c631972347034c1cc02fcc7d02ff01099cfe1c6989840ac213923629113aa8bad713ccf0fe4ce13264fb32b8b0fe372da382544a", + "3d55176acea4a7e3a65ffa9fb10a7a1767199cf077cee9f71532d67cd7c73c9f93cfc37ccdcc1fdef50aad46a504a650d298d597a3a9fa95c6c40cb71fa5e725", + "d07713c005de96dd21d2eb8bbeca66746ea51a31ae922a3e74864889540a48db27d7e4c90311638b224bf0201b501891754848113c266108d0adb13db71909c7", + "58983c21433d950caa23e4bc18543b8e601c204318532152daf5e159a0cd1480183d29285c05f129cb0cc3164687928086ffe380158df1d394c6ac0d4288bca8", + "8100a8dc528d2b682ab4250801ba33f02a3e94c54dac0ae1482aa21f51ef3a82f3807e6facb0aeb05947bf7aa2adcb034356f90fa4560ede02201a37e411ec1a", + "07025f1bb6c784f3fe49de5c14b936a5acacacaab33f6ac4d0e00ab6a12483d6bec00b4fe67c7ca5cc508c2a53efb5bfa5398769d843ff0d9e8b14d36a01a77f", + "ba6aefd972b6186e027a76273a4a723321a3f580cfa894da5a9ce8e721c828552c64dacee3a7fd2d743b5c35ad0c8efa71f8ce99bf96334710e2c2346e8f3c52", + "e0721e02517aedfa4e7e9ba503e025fd46e714566dc889a84cbfe56a55dfbe2fc4938ac4120588335deac8ef3fa229adc9647f54ad2e3472234f9b34efc46543", + "b6292669ccd38d5f01caae96ba272c76a879a45743afa0725d83b9ebb26665b731f1848c52f11972b6644f554c064fa90780dbbbf3a89d4fc31f67df3e5857ef", + "2319e3789c47e2daa5fe807f61bec2a1a6537fa03f19ff32e87eecbfd64b7e0e8ccff439ac333b040f19b0c4ddd11a61e24ac1fe0f10a039806c5dcc0da3d115", + "f59711d44a031d5f97a9413c065d1e614c417ede998590325f49bad2fd444d3e4418be19aec4e11449ac1a57207898bc57d76a1bcf3566292c20c683a5c4648f", + "df0a9d0c212843a6a934e3902b2dd30d17fba5f969d2030b12a546d8a6a45e80cf5635f071f0452e9c919275da99bed51eb1173c1af0518726b75b0ec3bae2b5", + "a3eb6e6c7bf2fb8b28bfe8b15e15bb500f781ecc86f778c3a4e655fc5869bf2846a245d4e33b7b14436a17e63be79b36655c226a50ffbc7124207b0202342db5", + "56d4cbcd070563426a017069425c2cd2ae540668287a5fb9dac432eb8ab1a353a30f2fe1f40d83333afe696a267795408a92fe7da07a0c1814cf77f36e105ee8", + "e59b9987d428b3eda37d80abdb16cd2b0aef674c2b1dda4432ea91ee6c935c684b48b4428a8cc740e579a30deff35a803013820dd23f14ae1d8413b5c8672aec", + "cd9fcc99f99d4cc16d031900b2a736e1508db4b586814e6345857f354a70ccecb1df3b50a19adaf43c278efa423ff4bb6c523ec7fd7859b97b168a7ebff8467c", + "0602185d8c3a78738b99164b8bc6ffb21c7debebbf806372e0da44d121545597b9c662a255dc31542cf995ecbe6a50fb5e6e0ee4ef240fe557eded1188087e86", + "c08afa5b927bf08097afc5fff9ca4e7800125c1f52f2af3553fa2b89e1e3015c4f87d5e0a48956ad31450b083dad147ffb5ec03434a26830cf37d103ab50c5da", + "36f1e1c11d6ef6bc3b536d505d544a871522c5c2a253067ec9933b6ec25464daf985525f5b9560a16d890259ac1bb5cc67c0c469cde133def000ea1d686f4f5d", + "bf2ab2e2470f5438c3b689e66e7686fffa0cb1e1798ad3a86ff99075bf6138e33d9c0ce59afb24ac67a02af34428191a9a0a6041c07471b7c3b1a752d6fc0b8b", + "d400601f9728ccc4c92342d9787d8d28ab323af375ca5624b4bb91d17271fbae862e413be73f1f68e615b8c5c391be0dbd9144746eb339ad541547ba9c468a17", + "79fe2fe157eb85a038abb8ebbc647731d2c83f51b0ac6ee14aa284cb6a3549a4dcceb300740a825f52f5fb30b03b8c4d8b0f4aa67a63f4a94e3303c4eda4c02b", + "75351313b52a8529298d8c186b1768666dcca8595317d7a4816eb88c062020c0c8efc554bb341b64688db5ccafc35f3c3cd09d6564b36d7b04a248e146980d4b", + "e3128b1d311d02179d7f25f97a5a8bee2cc8c86303644fcd664e157d1fef00f23e46f9a5e8e5c890ce565bb6abd4302ce06469d52a5bd53e1c5a54d04649dc03", + "c2382a72d2d3ace9d5933d00b60827ed380cda08d0ba5f6dd41e29ee6dbe8ecb9235f06be95d83b6816a2fb7a5ad47035e8a4b69a4884b99e4bece58cab25d44", + "6b1c69460bbd50ac2ed6f32e6e887cfed407d47dcf0aaa60387fe320d780bd03eab6d7baeb2a07d10cd552a300341354ea9a5f03183a623f92a2d4d9f00926af", + "6cda206c80cdc9c44ba990e0328c314f819b142d00630404c48c05dc76d1b00ce4d72fc6a48e1469ddef609412c364820854214b4869af090f00d3c1ba443e1b", + "7ffc8c26fbd6a0f7a609e6e1939f6a9edf1b0b066641fb76c4f9602ed748d11602496b35355b1aa255850a509d2f8ee18c8f3e1d7dcbc37a136598f56a59ed17", + "70de1f08dd4e09d5fc151f17fc991a23abfc05104290d50468882efaf582b6ec2f14f577c0d68c3ad06626916e3c86e6daab6c53e5163e82b6bd0ce49fc0d8df", + "4f81935756ed35ee2058ee0c6a6110d6fac5cb6a4f46aa9411603f99965823b6da4838276c5c06bc7880e376d92758369ee7305bcec8d3cfd28ccabb7b4f0579", + "abcb61cb3683d18f27ad527908ed2d32a0426cb7bb4bf18061903a7dc42e7e76f982382304d18af8c80d91dd58dd47af76f8e2c36e28af2476b4bccf82e89fdf", + "02d261ad56a526331b643dd2186de9a82e72a58223cd1e723686c53d869b83b94632b7b647ab2afc0d522e29da3a5615b741d82852e0df41b66007dbcba90543", + "c5832741fa30c5436823015383d297ff4c4a5d7276c3f902122066e04be5431b1a85faf73b918434f9300963d1dea9e8ac3924ef490226edeea5f743e410669f", + "cfaeab268cd075a5a6aed515023a032d54f2f2ff733ce0cbc78db51db4504d675923f82746d6594606ad5d67734b11a67cc6a468c2032e43ca1a94c6273a985e", + "860850f92eb268272b67d133609bd64e34f61bf03f4c1738645c17fec818465d7ecd2be2907641130025fda79470ab731646e7f69440e8367ea76ac4cee8a1df", + "84b154ed29bbedefa648286839046f4b5aa34430e2d67f7496e4c39f2c7ea78995f69e1292200016f16ac3b37700e6c7e7861afc396b64a59a1dbf47a55c4bbc", + "aeeec260a5d8eff5ccab8b95da435a63ed7a21ea7fc7559413fd617e33609f8c290e64bbacc528f6c080262288b0f0a3219be223c991bee92e72349593e67638", + "8ad78a9f26601d127e8d2f2f976e63d19a054a17dcf59e0f013ab54a6887bbdffde7aaae117e0fbf3271016595b9d9c712c01b2c53e9655a382bc4522e616645", + "8934159dade1ac74147dfa282c75954fcef443ef25f80dfe9fb6ea633b8545111d08b34ef43fff17026c7964f5deac6d2b3c29dacf2747f022df5967dfdc1a0a", + "cd36dd0b240614cf2fa2b9e959679dcdd72ec0cd58a43da3790a92f6cdeb9e1e795e478a0a47d371100d340c5cedcdbbc9e68b3f460818e5bdff7b4cda4c2744", + "00df4e099b807137a85990f49d3a94315e5a5f7f7a6076b303e96b056fb93800111f479628e2f8db59aeb6ac70c3b61f51f9b46e80ffdeae25ebddb4af6cb4ee", + "2b9c955e6caed4b7c9e246b86f9a1726e810c59d126cee66ed71bf015b83558a4b6d84d18dc3ff4620c2ffb722359fdef85ba0d4e2d22ecbe0ed784f99afe587", + "181df0a261a2f7d29ea5a15772715105d450a4b6c236f699f462d60ca76487feedfc9f5eb92df838e8fb5dc3694e84c5e0f4a10b761f506762be052c745a6ee8", + "21fb203458bf3a7e9a80439f9a902899cd5de0139dfd56f7110c9dec8437b26bda63de2f565926d85edb1d6c6825669743dd9992653d13979544d5dc8228bfaa", + "ef021f29c5ffb830e64b9aa9058dd660fd2fcb81c497a7e698bcfbf59de5ad4a86ff93c10a4b9d1ae5774725f9072dcde9e1f199bab91f8bff921864aa502eee", + "b3cfda40526b7f1d37569bdfcdf911e5a6efe6b2ec90a0454c47b2c046bf130fc3b352b34df4813d48d33ab8e269b69b075676cb6d00a8dcf9e1f967ec191b2c", + "b4c6c3b267071eefb9c8c72e0e2b941293641f8673cb70c1cc26ad1e73cf141755860ad19b34c2f34ed35bb52ec4507cc1fe59047743a5f0c6febde625e26091", + "57a34f2bcca60d4b85103b830c9d7952a416be5263ae429c9e5e53fe8590a8f78ec65a51109ea85dcdf7b6223f9f2b340539fad81923dbf8edabf95129e4dff6", + "9cf46662fcd61a232277b685663b8b5da832dfd9a3b8ccfeec993ec6ac415ad07e048adfe414df272770dba867da5c1224c6fd0aa0c2187d426ac647e9887361", + "5ce1042ab4d542c2f9ee9d17262af8164098935bef173d0e18489b04841746cd2f2df866bd7da6e5ef9024c648023ec723ab9c62fd80285739d84f15d2ab515a", + "8488396bd4a8729b7a473178f232dadf3f0f8e22678ba5a43e041e72da1e2cf82194c307207a54cb8156293339eaec693ff66bfcd5efc65e95e4ecaf54530abd", + "f598da901c3835bca560779037dfde9f0c51dc61c0b760fc1522d7b470ee63f5bdc6498476e86049ad86e4e21af2854a984cc905427d2f17f66b1f41c3da6f61", + "5f93269798cf02132107337660a8d7a177354c0212eb93e555e7c37a08aef3d8dce01217011cd965c04dd2c105f2e2b6cae5e4e6bcaf09dfbee3e0a6a6357c37", + "0ecf581d47bac9230986faabd70c2f5b80e91066f0ec55a842937882286d2ca007bb4e973b0b091d52167ff7c4009c7ab4ad38fff1dceacdb7be81ef4a452952", + "5aeca8abe1528582b2a307b4009585498a3d467ca6101cb0c5126f9976056e9ffc123cc20c302b2a737f492c75d21f01512c90ca0541dfa56e950a321dcb28d8", + "732fbf8f1cb2b8329263ede27858fe46f8d3354d376bcda0548e7ce1fa9dd11f85eb661fe950b543aa635ca4d3f04ede5b32d6b656e5ce1c44d35c4a6c56cff8", + "d5e938735d63788c80100aefd18648d18cf272f69f20ff24cfe2895c088ad08b0104da1672a4eb26fc52545cc7d7a01b266cf546c403c45bd129eb41bdd9200b", + "65a245b49352ee297d91af8c8be00528ac6e046dd83ac7bd465a98816dd68f3e00e1ae8f895327a7e9a8c9326598379a29c9fc91ec0c6eef08f3e2b216c11008", + "c95654b63019130ab45dd0fb4941b98aeb3af2a123913eca2ce99b3e97410a7bf8661cc7fbaa2bc1cf2b13113b1ed40a0118b88e5fffc3542759ea007ed4c58d", + "1eb262f38fa494431f017dad44c0dfb69324ac032f04b657fc91a88647bb74760f24e7c956514f0cf002990b182c1642b9b2426e96a61187e4e012f00e217d84", + "3b955aeebfa5151ac1ab8e3f5cc1e3767084c842a575d36269836e97353d41622b731dddcd5f269550a3a5b87be1e90326340b6e0e62555815d9600597ac6ef9", + "68289f6605473ba0e4f241baf7477a9885426a858f19ef2a18b0d40ef8e41282ed5526b519799e270f13881327918278755711071d8511fe963e3b5606aa3716", + "80a33787542612c38f6bcd7cd86cab460227509b1cbad5ec408a91413d51155a0476dadbf3a2518e4a6e77cc346622e347a469bf8baa5f04eb2d98705355d063", + "34629bc6d831391c4cdf8af1b4b7b6b8e8ee17cf98c70e5dd586cd99f14b11df945166236a9571e6d591bb83ee4d164d46f6b9d8ef86ff865a81bfb91b00424b", + "8b7cc339163863bb4383e542b0ef0e7cf36b84ad932cdf5a80419ec9ad692e7a7e784d2c7cb3796a18b8f800035f3aa06c824100611120a7bdeb35618ccb81b7", + "4f084e4939dd5a7f5a658fad58a18a15c25c32ec1c7fd5c5c6c3e892b3971aeaac308304ef17b1c47239ea4bb398b3fd6d4528d8de8e768ae0f1a5a5c6b5c297", + "48f407a1af5b8009b2051742e8cf5cd5656669e7d722ee8e7bd202060849442168d8facc117c012bfb7bf449d99befff6a34aea203f1d8d352722be5014ec818", + "a6aa82cd1e426f9a73bfa39a29037876114655b8c22d6d3ff8b638ae7dea6b17843e09e52eb66fa1e475e4a8a3de429b7d0f4a776fcb8bdc9b9fede7d52e815f", + "5817027d6bdd00c5dd10ac593cd560372270775a18526d7e6f13872a2e20eab664625be7168ac4bd7c9e0ce7fc4099e0f48442e2c767191c6e1284e9b2ccea8c", + "08e41028340a45c74e4052b3a8d6389e22e043a1adab5e28d97619450d723469b620caa519b81c14523854f619fd3027e3847bd03276e60604a80ddb4de876d6", + "130b8420537eb07d72abda07c85acbd8b9a44f16321dd0422145f809673d30f2b5321326e2bff317ef3fef983c51c4f8ab24a325d298e34afce569a82555774c", + "ac49b844afaa012e31c474ca263648844fd2f6307992c2f752aca02c3828965175794deee2d2ee95c61cd284f6b5a2d75e2ef2b29ee8149e77fb81447b2fd04b", + "b9d7ca81cc60bb9578e44024e5a0a0be80f27336a6a9f4e53df3999cb191280b090e2ac2d29c5baad9d71415bdc129e69aa2667af6a7fd5e189fccdcee817340", + "a755e113386572c75ced61d719706070b9146048e42a9f8cd35667a088b42f08808abdf77e618abd959afc757379ca2c00bcc1a48390fa2bff618b1e0078a613", + "a73c7debed326f1c0db0795ee7d6e3946894b826b1f8101c56c823ba17168312e7f53fc7dbe52c3e11e69852c40485e2ef182477862ea6a34ec136e2dfeea6f4", + "6cb8f9d52c56d82cac28f39ea1593e8bb2506293ac0d68376a1709b62a46df14a4ae64b2d8fab76733a1ced2d548e3f3c6fcb49d40c3d5808e449cd83d1c2aa2", + "683fa2b2369a10162c1c1c7b24bc970ee67da220564f32203f625696c0352a0b9ad96624362d952d84463c1106a2dba7a092599884b35a0b89c8f1b6a9b5a61e", + "aad9ad44610118b77d508aeb1bbcd1c1b7d0171397fb510a401bbc0ec34623670d86a2dc3c8f3ab5a2044df730256727545f0860ce21a1eac717dfc48f5d228e", + "c42578de23b4c987d5e1ac4d689ed5de4b0417f9704bc6bce969fa13471585d62c2cb1212a944f397fc9ca2c3747c3beb694ec4c5be68828dda53ef43faec6c0", + "470f00841ee8244e63ed2c7ea30e2e419897c197462ecccecf713b42a5065fff5914bc9b79affe8f6b657875e789ae213bd914cd35bd174d46e9d18bd843773d", + "34fc4213730f47a5e9a3580f643e12945cfcb31bf206f6ad450ce528da3fa432e005d6b0ecce10dca7c5995f6aacc5150e1b009e19751e8309f8859531844374", + "fb3c1f0f56a56f8e316fdf5d853c8c872c39635d083634c3904fc3ac07d1b578e85ff0e480e92d44ade33b62e893ee32343e79ddf6ef292e89b582d312502314", + "c7c97fc65dd2b9e3d3d607d31598d3f84261e9919251e9c8e57bb5f829377d5f73eabbed55c6c381180f29ad02e5be797ffec7e57bdecbc50ad3d062f0993ab0", + "a57a49cdbe67ae7d9f797bb5cc7efc2df07f4e1b15955f85dae74b76e2ecb85afb6cd9eeed8888d5ca3ec5ab65d27a7b19e578475760a045ac3c92e13a938e77", + "c7143fce9614a17fd653aeb140726dc9c3dbb1de6cc581b2726897ec24b7a50359ad492243be66d9edd8c933b5b80e0b91bb61ea98056006516976fae8d99a35", + "65bb58d07f937e2d3c7e65385f9c54730b704105ccdb691f6e146d4ee8f6c086f49511035110a9ad6031fdceb943e0f9613bcb276dd40f0624ef0f924f809783", + "e540277f683b1186dd3b5b3f61433396581a35feb12002be8c6a6231fc40ffa70f08081bc58b2d94f7649543614a435faa2d62110e13dabc7b86629b63af9c24", + "418500878c5fbcb584c432f4285e05e49f2e3e075399a0dbfcf874ebf8c03d02bf16bc6989d161c77ca0786b05053c6c709433712319192128835cf0b660595b", + "889090dbb1944bdc9433ee5ef1010c7a4a24a8e71ecea8e12a31318ce49dcab0aca5c3802334aab2cc84b14c6b9321fe586bf3f876f19cd406eb1127fb944801", + "53b6a28910aa92e27e536fb549cf9b9918791060898e0b9fe183577ff43b5e9c7689c745b32e412269837c31b89e6cc12bf76e13cad366b74ece48bb85fd09e9", + "7c092080c6a80d672409d081d3d177106bcd63567785140719490950ae07ae8fcaabbaaab330cfbcf7374482c220af2eadeeb73dcbb35ed823344e144e7d4899", + "9ccde566d2400509181111f32dde4cd63209fe59a30c114546ad2776d889a41bad8fa1bb468cb2f9d42ca9928a7770fef8e8ba4d0c812d9a1e75c3d8d2ccd75a", + "6e293bf5d03fe43977cfe3f57ccdb3ae282a85455dca33f37f4b74f8398cc612433d755cbec412f8f82a3bd3bc4a278f7ecd0dfa9bbdc40be7a787c8f159b2df", + "c56546fb2178456f336164c18b90deffc83ae2b5a3aca77b6884d36d2c1db39501b3e65e36c758c66e3188451fdb3515ee162c001f06c3e8cb573adf30f7a101", + "6f82f89f299ebca2fe014b59bffe1aa84e88b1915fe256afb646fd8448af2b8891a7fab37a4ea6f9a50e6c317039d8cf878f4c8e1a0dd464f0b4d6ff1c7ea853", + "2b8599ff9c3d6198637ad51e57d1998b0d75313fe2dd61a533c964a6dd9607c6f723e9452ce46e014b1c1d6de77ba5b88c914d1c597bf1eae13474b4290e89b2", + "08bf346d38e1df06c8260edb1da75579275948d5c0a0aa9ed2886f8856de5417a156998758f5b17e52f101ca957a71137473dfd18d7d209c4c10d9233c93691d", + "6df2156d773114d310b63db9ee5350d77e6bcf25b05fcd910f9b31bc42bb13fe8225ebcb2a23a62280777b6bf74e2cd0917c7640b43defe468cd1e18c943c66a", + "7c7038bc13a91151828a5ba82b4a96040f258a4dfb1b1373f0d359168afb0517a20b28a12d3644046be66b8d08d8ae7f6a923ea1c00187c6d11dc502bac71305", + "bcd1b30d808fb739b987cbf154bea00da9d40380b861d4c1d6377122dadd61c0e59018b71941cfb62e00dcd70aeb9abf0473e80f0a7eca6b6dea246ab229dd2b", + "7ed4468d968530fe7ab2c33540b26d8c3bd3ed44b34fbe8c2a9d7f805b5ada0ea252eeade4fce97f89728ad85bc8bb2430b1bef2cddd32c8446e59b8e8ba3c67", + "6d30b7c6ce8a3236c0ca2f8d728b1088ca06983a8043e621d5dcf0c537d13b08791edeb01a3cf0943ec1c890ab6e29b146a236cd46bcb9d93bf516fb67c63fe5", + "97fe03cef31438508911bded975980a66029305dc5e3fa8ad1b4fb22fcdf5a19a733320327d8f71ccf496cb3a44a77af56e3dde73d3a5f176896cc57c9a5ad99", + "785a9d0fbd21136dbce8fa7eafd63c9dad220052978416b31d9753eaa149097847ed9b30a65c70507eff01879149ed5cf0471d37798edc05abd56ad4a2cccb1d", + "ad408d2abddfd37b3bf34794c1a3371d928ed7fc8d966225333584c5665817832a37c07f0dc7cb5aa874cd7d20fe8fab8eabcb9b33d2e0841f6e200960899d95", + "97668f745b6032fc815d9579322769dccd9501a5080029b8ae826befb6742331bd9f76efeb3e2b8e81a9786b282f5068a3a2424697a77c41876b7e753f4c7767", + "26bb985f47e7fee0cfd252d4ef96bed42b9c370c1c6a3e8c9eb04ef7f7818b833a0d1f043ebafb911dc779e02740a02a44d3a1ea45ed4ad55e686c927cafe97e", + "5bfe2b1dcf7fe9b95088acedb575c19016c743b2e763bf5851ac407c9eda43715edfa48b4825492c5179593fff21351b76e8b7e034e4c53c79f61f29c479bd08", + "c76509ef72f4a6f9c9c40618ed52b2084f83502232e0ac8bdaf3264368e4d0180f6854c4abf4f6509c79caafc44cf3194afc57bd077bd7b3c9bda3d4b8775816", + "d66f2beab990e354ccb910e4e9c7ac618c7b63ef292a96b552341de78dc46d3ec8cfabc699b50af41fda39cf1b0173660923510ad67faedef5207cffe8641d20", + "7d8f0672992b79be3a364d8e5904f4ab713bbc8ab01b4f309ad8ccf223ce1034a860dcb0b00550612cc2fa17f2969e18f22e1427d254b4a82b3a03a3eb394adf", + "a56d6725bfb3de47c1414adf25fc8f0fc9846f6987722bc06366d5ca4e89722925ebbc881418844075397a0ca89842c7b9e9e07e1d9d183ebeb39e120b483bf7", + "af5e03d7fe60c67e10313344434e79485a03a758d6dce985574745763c1c5c77d4fb3e6fb12230368370993bf90feed0c5d1607524562d7c09c0c210ed393d7c", + "7a20540cc07bf72b582421fc342e82f52134b69841ec28ed189e2ea6a29dd2f82a640352d222b52f2911dc72a7dab31caadd80c6118f13c56b2a1e4373be0ea3", + "486f02c63e5467ea1fdde7e82bfacc2c1ba5d636d9f3d08b210da3f372f706ec218cc17ff60aef703bbe0c15c38ae55d286a684f864c78211ccab4178c92adba", + "1c7a5c1dedcd04a921788f7eb23361ca1953b04b9c7aec35d65ea3e4996db26f281278ea4ae666ad81027d98af57262cdbfa4c085f4210568c7e15eec7805114", + "9ce3fa9a860bdbd5378fd6d7b8b671c6cb7692910ce8f9b6cb4122cbcbe6ac06ca0422cef1225935053b7d193a81b9e972eb85a1d3074f14cbb5ec9f0573892d", + "a91187be5c371c4265c174fd4653b8ab708551f83d1fee1cc1479581bc006d6fb78fcc9a5dee1db3666f508f9780a37593ebcccf5fbed39667dc6361e921f779", + "4625767d7b1d3d3ed2fbc674af14e0244152f2a4021fcf3311505d89bd81e2f9f9a500c3b199914db49500b3c98d03ea93286751a686a3b875daab0ccd63b44f", + "43dfdfe1b014fed3a2acabb7f3e9a182f2aa18019d27e3e6cdcf31a15b428e91e7b08cf5e5c376fce2d8a28ff85ab0a0a1656edb4a0a91532620096d9a5a652d", + "279e3202be3989ba3112772585177487e4fe3ee3eab49c2f7fa7fe87cfe7b80d3e0355edff6d031e6c96c795db1c6f041880ec3824defacf9263820a8e7327de", + "ea2d066ac229d4d4b616a8bedec734325224e4b4e58f1ae6dad7e40c2da29196c3b1ea9571dacc81e87328caa0211e09027b0524aa3f4a849917b3586747ebbb", + "49f014f5c61822c899ab5cae51be4044a4495e777deb7da9b6d8490efbb87530adf293daf079f94c33b7044ef62e2e5bb3eb11e17304f8453ee6ce24f033ddb0", + "9233490344e5b0dc5912671b7ae54cee7730dbe1f4c7d92a4d3e3aab50571708db51dcf9c2944591db651db32d22935b86944969be77d5b5feae6c3840a8db26", + "b6e75e6f4c7f453b7465d25b5ac8c7196902eaa953875228c8634e16e2ae1f38bc3275304335f5989eccc1e34167d4e68d7719968fba8e2fe67947c35c48e806", + "cc14ca665af1483efbc3af80080e650d5046a3932f4f51f3fe90a0705ec25104adf07839265dc51d43401411246e474f0d5e5637af94767283d53e0617e981f4", + "230a1c857cb2e7852e41b647e90e4585d2d881e1734dc38955356e8dd7bff39053092c6b38e236e1899525647073dddf6895d64206325e7647f275567b255909", + "cbb65321ac436e2ffdab2936359ce49023f7dee7614ef28d173c3d27c5d1bffa51553d433f8ee3c9e49c05a2b883cce954c9a8093b80612a0cdd4732e041f995", + "3e7e570074337275efb51315588034c3cf0dddca20b4612e0bd5b881e7e5476d319ce4fe9f19186e4c0826f44f131eb048e65be242b1172c63badb123ab0cbe8", + "d32e9ec02d38d4e1b8249df8dcb00c5b9c68eb8922672e3505393b6a210ba56f9496e5ee0490ef387c3cdec061f06bc0382d9304cafbb8e0cd33d57029e62df2", + "8c1512466089f05b3775c262b62d22b83854a83218130b4ec91b3ccbd293d2a54302cecaab9b100c68d1e6ddc8f07cddbdfe6fdaaaf099cc09d6b725879c6369", + "91a7f61c97c2911e4c812ef71d780ad8fa788794561d08303fd1c1cb608a46a12563086ec5b39d471aed94fb0f6c678a43b8792932f9028d772a22768ea23a9b", + "4f6bb222a395e8b18f6ba155477aed3f0729ac9e83e16d31a2a8bc655422b837c891c6199e6f0d75799e3b691525c581953517f252c4b9e3a27a28fbaf49644c", + "5d06c07e7a646c413a501c3f4bb2fc38127de7509b7077c4d9b5613201c1aa02fd5f79d2745915dd57fbcb4ce08695f6efc0cb3d2d330e19b4b0e6004ea6471e", + "b96756e57909968f14b796a5d30f4c9d671472cf82c8cfb2caca7ac7a44ca0a14c9842d00c82e337502c94d5960aca4c492ea7b0df919ddf1aada2a275bb10d4", + "ff0a015e98db9c99f03977710aac3e658c0d896f6d71d618ba79dc6cf72ac75b7c038eb6862dede4543e145413a6368d69f5722c827ba3ef25b6ae6440d39276", + "5b21c5fd8868367612474fa2e70e9cfa2201ffeee8fafab5797ad58fefa17c9b5b107da4a3db6320baaf2c8617d5a51df914ae88da3867c2d41f0cc14fa67928", +} + +var goldenKeyed = []string{ + "10ebb67700b1868efb4417987acf4690ae9d972fb7a590c2f02871799aaa4786b5e996e8f0f4eb981fc214b005f42d2ff4233499391653df7aefcbc13fc51568", + "961f6dd1e4dd30f63901690c512e78e4b45e4742ed197c3c5e45c549fd25f2e4187b0bc9fe30492b16b0d0bc4ef9b0f34c7003fac09a5ef1532e69430234cebd", + "da2cfbe2d8409a0f38026113884f84b50156371ae304c4430173d08a99d9fb1b983164a3770706d537f49e0c916d9f32b95cc37a95b99d857436f0232c88a965", + "33d0825dddf7ada99b0e7e307104ad07ca9cfd9692214f1561356315e784f3e5a17e364ae9dbb14cb2036df932b77f4b292761365fb328de7afdc6d8998f5fc1", + "beaa5a3d08f3807143cf621d95cd690514d0b49efff9c91d24b59241ec0eefa5f60196d407048bba8d2146828ebcb0488d8842fd56bb4f6df8e19c4b4daab8ac", + "098084b51fd13deae5f4320de94a688ee07baea2800486689a8636117b46c1f4c1f6af7f74ae7c857600456a58a3af251dc4723a64cc7c0a5ab6d9cac91c20bb", + "6044540d560853eb1c57df0077dd381094781cdb9073e5b1b3d3f6c7829e12066bbaca96d989a690de72ca3133a83652ba284a6d62942b271ffa2620c9e75b1f", + "7a8cfe9b90f75f7ecb3acc053aaed6193112b6f6a4aeeb3f65d3de541942deb9e2228152a3c4bbbe72fc3b12629528cfbb09fe630f0474339f54abf453e2ed52", + "380beaf6ea7cc9365e270ef0e6f3a64fb902acae51dd5512f84259ad2c91f4bc4108db73192a5bbfb0cbcf71e46c3e21aee1c5e860dc96e8eb0b7b8426e6abe9", + "60fe3c4535e1b59d9a61ea8500bfac41a69dffb1ceadd9aca323e9a625b64da5763bad7226da02b9c8c4f1a5de140ac5a6c1124e4f718ce0b28ea47393aa6637", + "4fe181f54ad63a2983feaaf77d1e7235c2beb17fa328b6d9505bda327df19fc37f02c4b6f0368ce23147313a8e5738b5fa2a95b29de1c7f8264eb77b69f585cd", + "f228773ce3f3a42b5f144d63237a72d99693adb8837d0e112a8a0f8ffff2c362857ac49c11ec740d1500749dac9b1f4548108bf3155794dcc9e4082849e2b85b", + "962452a8455cc56c8511317e3b1f3b2c37df75f588e94325fdd77070359cf63a9ae6e930936fdf8e1e08ffca440cfb72c28f06d89a2151d1c46cd5b268ef8563", + "43d44bfa18768c59896bf7ed1765cb2d14af8c260266039099b25a603e4ddc5039d6ef3a91847d1088d401c0c7e847781a8a590d33a3c6cb4df0fab1c2f22355", + "dcffa9d58c2a4ca2cdbb0c7aa4c4c1d45165190089f4e983bb1c2cab4aaeff1fa2b5ee516fecd780540240bf37e56c8bcca7fab980e1e61c9400d8a9a5b14ac6", + "6fbf31b45ab0c0b8dad1c0f5f4061379912dde5aa922099a030b725c73346c524291adef89d2f6fd8dfcda6d07dad811a9314536c2915ed45da34947e83de34e", + "a0c65bddde8adef57282b04b11e7bc8aab105b99231b750c021f4a735cb1bcfab87553bba3abb0c3e64a0b6955285185a0bd35fb8cfde557329bebb1f629ee93", + "f99d815550558e81eca2f96718aed10d86f3f1cfb675cce06b0eff02f617c5a42c5aa760270f2679da2677c5aeb94f1142277f21c7f79f3c4f0cce4ed8ee62b1", + "95391da8fc7b917a2044b3d6f5374e1ca072b41454d572c7356c05fd4bc1e0f40b8bb8b4a9f6bce9be2c4623c399b0dca0dab05cb7281b71a21b0ebcd9e55670", + "04b9cd3d20d221c09ac86913d3dc63041989a9a1e694f1e639a3ba7e451840f750c2fc191d56ad61f2e7936bc0ac8e094b60caeed878c18799045402d61ceaf9", + "ec0e0ef707e4ed6c0c66f9e089e4954b058030d2dd86398fe84059631f9ee591d9d77375355149178c0cf8f8e7c49ed2a5e4f95488a2247067c208510fadc44c", + "9a37cce273b79c09913677510eaf7688e89b3314d3532fd2764c39de022a2945b5710d13517af8ddc0316624e73bec1ce67df15228302036f330ab0cb4d218dd", + "4cf9bb8fb3d4de8b38b2f262d3c40f46dfe747e8fc0a414c193d9fcf753106ce47a18f172f12e8a2f1c26726545358e5ee28c9e2213a8787aafbc516d2343152", + "64e0c63af9c808fd893137129867fd91939d53f2af04be4fa268006100069b2d69daa5c5d8ed7fddcb2a70eeecdf2b105dd46a1e3b7311728f639ab489326bc9", + "5e9c93158d659b2def06b0c3c7565045542662d6eee8a96a89b78ade09fe8b3dcc096d4fe48815d88d8f82620156602af541955e1f6ca30dce14e254c326b88f", + "7775dff889458dd11aef417276853e21335eb88e4dec9cfb4e9edb49820088551a2ca60339f12066101169f0dfe84b098fddb148d9da6b3d613df263889ad64b", + "f0d2805afbb91f743951351a6d024f9353a23c7ce1fc2b051b3a8b968c233f46f50f806ecb1568ffaa0b60661e334b21dde04f8fa155ac740eeb42e20b60d764", + "86a2af316e7d7754201b942e275364ac12ea8962ab5bd8d7fb276dc5fbffc8f9a28cae4e4867df6780d9b72524160927c855da5b6078e0b554aa91e31cb9ca1d", + "10bdf0caa0802705e706369baf8a3f79d72c0a03a80675a7bbb00be3a45e516424d1ee88efb56f6d5777545ae6e27765c3a8f5e493fc308915638933a1dfee55", + "b01781092b1748459e2e4ec178696627bf4ebafebba774ecf018b79a68aeb84917bf0b84bb79d17b743151144cd66b7b33a4b9e52c76c4e112050ff5385b7f0b", + "c6dbc61dec6eaeac81e3d5f755203c8e220551534a0b2fd105a91889945a638550204f44093dd998c076205dffad703a0e5cd3c7f438a7e634cd59fededb539e", + "eba51acffb4cea31db4b8d87e9bf7dd48fe97b0253ae67aa580f9ac4a9d941f2bea518ee286818cc9f633f2a3b9fb68e594b48cdd6d515bf1d52ba6c85a203a7", + "86221f3ada52037b72224f105d7999231c5e5534d03da9d9c0a12acb68460cd375daf8e24386286f9668f72326dbf99ba094392437d398e95bb8161d717f8991", + "5595e05c13a7ec4dc8f41fb70cb50a71bce17c024ff6de7af618d0cc4e9c32d9570d6d3ea45b86525491030c0d8f2b1836d5778c1ce735c17707df364d054347", + "ce0f4f6aca89590a37fe034dd74dd5fa65eb1cbd0a41508aaddc09351a3cea6d18cb2189c54b700c009f4cbf0521c7ea01be61c5ae09cb54f27bc1b44d658c82", + "7ee80b06a215a3bca970c77cda8761822bc103d44fa4b33f4d07dcb997e36d55298bceae12241b3fa07fa63be5576068da387b8d5859aeab701369848b176d42", + "940a84b6a84d109aab208c024c6ce9647676ba0aaa11f86dbb7018f9fd2220a6d901a9027f9abcf935372727cbf09ebd61a2a2eeb87653e8ecad1bab85dc8327", + "2020b78264a82d9f4151141adba8d44bf20c5ec062eee9b595a11f9e84901bf148f298e0c9f8777dcdbc7cc4670aac356cc2ad8ccb1629f16f6a76bcefbee760", + "d1b897b0e075ba68ab572adf9d9c436663e43eb3d8e62d92fc49c9be214e6f27873fe215a65170e6bea902408a25b49506f47babd07cecf7113ec10c5dd31252", + "b14d0c62abfa469a357177e594c10c194243ed2025ab8aa5ad2fa41ad318e0ff48cd5e60bec07b13634a711d2326e488a985f31e31153399e73088efc86a5c55", + "4169c5cc808d2697dc2a82430dc23e3cd356dc70a94566810502b8d655b39abf9e7f902fe717e0389219859e1945df1af6ada42e4ccda55a197b7100a30c30a1", + "258a4edb113d66c839c8b1c91f15f35ade609f11cd7f8681a4045b9fef7b0b24c82cda06a5f2067b368825e3914e53d6948ede92efd6e8387fa2e537239b5bee", + "79d2d8696d30f30fb34657761171a11e6c3f1e64cbe7bebee159cb95bfaf812b4f411e2f26d9c421dc2c284a3342d823ec293849e42d1e46b0a4ac1e3c86abaa", + "8b9436010dc5dee992ae38aea97f2cd63b946d94fedd2ec9671dcde3bd4ce9564d555c66c15bb2b900df72edb6b891ebcadfeff63c9ea4036a998be7973981e7", + "c8f68e696ed28242bf997f5b3b34959508e42d613810f1e2a435c96ed2ff560c7022f361a9234b9837feee90bf47922ee0fd5f8ddf823718d86d1e16c6090071", + "b02d3eee4860d5868b2c39ce39bfe81011290564dd678c85e8783f29302dfc1399ba95b6b53cd9ebbf400cca1db0ab67e19a325f2d115812d25d00978ad1bca4", + "7693ea73af3ac4dad21ca0d8da85b3118a7d1c6024cfaf557699868217bc0c2f44a199bc6c0edd519798ba05bd5b1b4484346a47c2cadf6bf30b785cc88b2baf", + "a0e5c1c0031c02e48b7f09a5e896ee9aef2f17fc9e18e997d7f6cac7ae316422c2b1e77984e5f3a73cb45deed5d3f84600105e6ee38f2d090c7d0442ea34c46d", + "41daa6adcfdb69f1440c37b596440165c15ada596813e2e22f060fcd551f24dee8e04ba6890387886ceec4a7a0d7fc6b44506392ec3822c0d8c1acfc7d5aebe8", + "14d4d40d5984d84c5cf7523b7798b254e275a3a8cc0a1bd06ebc0bee726856acc3cbf516ff667cda2058ad5c3412254460a82c92187041363cc77a4dc215e487", + "d0e7a1e2b9a447fee83e2277e9ff8010c2f375ae12fa7aaa8ca5a6317868a26a367a0b69fbc1cf32a55d34eb370663016f3d2110230eba754028a56f54acf57c", + "e771aa8db5a3e043e8178f39a0857ba04a3f18e4aa05743cf8d222b0b095825350ba422f63382a23d92e4149074e816a36c1cd28284d146267940b31f8818ea2", + "feb4fd6f9e87a56bef398b3284d2bda5b5b0e166583a66b61e538457ff0584872c21a32962b9928ffab58de4af2edd4e15d8b35570523207ff4e2a5aa7754caa", + "462f17bf005fb1c1b9e671779f665209ec2873e3e411f98dabf240a1d5ec3f95ce6796b6fc23fe171903b502023467dec7273ff74879b92967a2a43a5a183d33", + "d3338193b64553dbd38d144bea71c5915bb110e2d88180dbc5db364fd6171df317fc7268831b5aef75e4342b2fad8797ba39eddcef80e6ec08159350b1ad696d", + "e1590d585a3d39f7cb599abd479070966409a6846d4377acf4471d065d5db94129cc9be92573b05ed226be1e9b7cb0cabe87918589f80dadd4ef5ef25a93d28e", + "f8f3726ac5a26cc80132493a6fedcb0e60760c09cfc84cad178175986819665e76842d7b9fedf76dddebf5d3f56faaad4477587af21606d396ae570d8e719af2", + "30186055c07949948183c850e9a756cc09937e247d9d928e869e20bafc3cd9721719d34e04a0899b92c736084550186886efba2e790d8be6ebf040b209c439a4", + "f3c4276cb863637712c241c444c5cc1e3554e0fddb174d035819dd83eb700b4ce88df3ab3841ba02085e1a99b4e17310c5341075c0458ba376c95a6818fbb3e2", + "0aa007c4dd9d5832393040a1583c930bca7dc5e77ea53add7e2b3f7c8e231368043520d4a3ef53c969b6bbfd025946f632bd7f765d53c21003b8f983f75e2a6a", + "08e9464720533b23a04ec24f7ae8c103145f765387d738777d3d343477fd1c58db052142cab754ea674378e18766c53542f71970171cc4f81694246b717d7564", + "d37ff7ad297993e7ec21e0f1b4b5ae719cdc83c5db687527f27516cbffa822888a6810ee5c1ca7bfe3321119be1ab7bfa0a502671c8329494df7ad6f522d440f", + "dd9042f6e464dcf86b1262f6accfafbd8cfd902ed3ed89abf78ffa482dbdeeb6969842394c9a1168ae3d481a017842f660002d42447c6b22f7b72f21aae021c9", + "bd965bf31e87d70327536f2a341cebc4768eca275fa05ef98f7f1b71a0351298de006fba73fe6733ed01d75801b4a928e54231b38e38c562b2e33ea1284992fa", + "65676d800617972fbd87e4b9514e1c67402b7a331096d3bfac22f1abb95374abc942f16e9ab0ead33b87c91968a6e509e119ff07787b3ef483e1dcdccf6e3022", + "939fa189699c5d2c81ddd1ffc1fa207c970b6a3685bb29ce1d3e99d42f2f7442da53e95a72907314f4588399a3ff5b0a92beb3f6be2694f9f86ecf2952d5b41c", + "c516541701863f91005f314108ceece3c643e04fc8c42fd2ff556220e616aaa6a48aeb97a84bad74782e8dff96a1a2fa949339d722edcaa32b57067041df88cc", + "987fd6e0d6857c553eaebb3d34970a2c2f6e89a3548f492521722b80a1c21a153892346d2cba6444212d56da9a26e324dccbc0dcde85d4d2ee4399eec5a64e8f", + "ae56deb1c2328d9c4017706bce6e99d41349053ba9d336d677c4c27d9fd50ae6aee17e853154e1f4fe7672346da2eaa31eea53fcf24a22804f11d03da6abfc2b", + "49d6a608c9bde4491870498572ac31aac3fa40938b38a7818f72383eb040ad39532bc06571e13d767e6945ab77c0bdc3b0284253343f9f6c1244ebf2ff0df866", + "da582ad8c5370b4469af862aa6467a2293b2b28bd80ae0e91f425ad3d47249fdf98825cc86f14028c3308c9804c78bfeeeee461444ce243687e1a50522456a1d", + "d5266aa3331194aef852eed86d7b5b2633a0af1c735906f2e13279f14931a9fc3b0eac5ce9245273bd1aa92905abe16278ef7efd47694789a7283b77da3c70f8", + "2962734c28252186a9a1111c732ad4de4506d4b4480916303eb7991d659ccda07a9911914bc75c418ab7a4541757ad054796e26797feaf36e9f6ad43f14b35a4", + "e8b79ec5d06e111bdfafd71e9f5760f00ac8ac5d8bf768f9ff6f08b8f026096b1cc3a4c973333019f1e3553e77da3f98cb9f542e0a90e5f8a940cc58e59844b3", + "dfb320c44f9d41d1efdcc015f08dd5539e526e39c87d509ae6812a969e5431bf4fa7d91ffd03b981e0d544cf72d7b1c0374f8801482e6dea2ef903877eba675e", + "d88675118fdb55a5fb365ac2af1d217bf526ce1ee9c94b2f0090b2c58a06ca58187d7fe57c7bed9d26fca067b4110eefcd9a0a345de872abe20de368001b0745", + "b893f2fc41f7b0dd6e2f6aa2e0370c0cff7df09e3acfcc0e920b6e6fad0ef747c40668417d342b80d2351e8c175f20897a062e9765e6c67b539b6ba8b9170545", + "6c67ec5697accd235c59b486d7b70baeedcbd4aa64ebd4eef3c7eac189561a726250aec4d48cadcafbbe2ce3c16ce2d691a8cce06e8879556d4483ed7165c063", + "f1aa2b044f8f0c638a3f362e677b5d891d6fd2ab0765f6ee1e4987de057ead357883d9b405b9d609eea1b869d97fb16d9b51017c553f3b93c0a1e0f1296fedcd", + "cbaa259572d4aebfc1917acddc582b9f8dfaa928a198ca7acd0f2aa76a134a90252e6298a65b08186a350d5b7626699f8cb721a3ea5921b753ae3a2dce24ba3a", + "fa1549c9796cd4d303dcf452c1fbd5744fd9b9b47003d920b92de34839d07ef2a29ded68f6fc9e6c45e071a2e48bd50c5084e96b657dd0404045a1ddefe282ed", + "5cf2ac897ab444dcb5c8d87c495dbdb34e1838b6b629427caa51702ad0f9688525f13bec503a3c3a2c80a65e0b5715e8afab00ffa56ec455a49a1ad30aa24fcd", + "9aaf80207bace17bb7ab145757d5696bde32406ef22b44292ef65d4519c3bb2ad41a59b62cc3e94b6fa96d32a7faadae28af7d35097219aa3fd8cda31e40c275", + "af88b163402c86745cb650c2988fb95211b94b03ef290eed9662034241fd51cf398f8073e369354c43eae1052f9b63b08191caa138aa54fea889cc7024236897", + "48fa7d64e1ceee27b9864db5ada4b53d00c9bc7626555813d3cd6730ab3cc06ff342d727905e33171bde6e8476e77fb1720861e94b73a2c538d254746285f430", + "0e6fd97a85e904f87bfe85bbeb34f69e1f18105cf4ed4f87aec36c6e8b5f68bd2a6f3dc8a9ecb2b61db4eedb6b2ea10bf9cb0251fb0f8b344abf7f366b6de5ab", + "06622da5787176287fdc8fed440bad187d830099c94e6d04c8e9c954cda70c8bb9e1fc4a6d0baa831b9b78ef6648681a4867a11da93ee36e5e6a37d87fc63f6f", + "1da6772b58fabf9c61f68d412c82f182c0236d7d575ef0b58dd22458d643cd1dfc93b03871c316d8430d312995d4197f0874c99172ba004a01ee295abac24e46", + "3cd2d9320b7b1d5fb9aab951a76023fa667be14a9124e394513918a3f44096ae4904ba0ffc150b63bc7ab1eeb9a6e257e5c8f000a70394a5afd842715de15f29", + "04cdc14f7434e0b4be70cb41db4c779a88eaef6accebcb41f2d42fffe7f32a8e281b5c103a27021d0d08362250753cdf70292195a53a48728ceb5844c2d98bab", + "9071b7a8a075d0095b8fb3ae5113785735ab98e2b52faf91d5b89e44aac5b5d4ebbf91223b0ff4c71905da55342e64655d6ef8c89a4768c3f93a6dc0366b5bc8", + "ebb30240dd96c7bc8d0abe49aa4edcbb4afdc51ff9aaf720d3f9e7fbb0f9c6d6571350501769fc4ebd0b2141247ff400d4fd4be414edf37757bb90a32ac5c65a", + "8532c58bf3c8015d9d1cbe00eef1f5082f8f3632fbe9f1ed4f9dfb1fa79e8283066d77c44c4af943d76b300364aecbd0648c8a8939bd204123f4b56260422dec", + "fe9846d64f7c7708696f840e2d76cb4408b6595c2f81ec6a28a7f2f20cb88cfe6ac0b9e9b8244f08bd7095c350c1d0842f64fb01bb7f532dfcd47371b0aeeb79", + "28f17ea6fb6c42092dc264257e29746321fb5bdaea9873c2a7fa9d8f53818e899e161bc77dfe8090afd82bf2266c5c1bc930a8d1547624439e662ef695f26f24", + "ec6b7d7f030d4850acae3cb615c21dd25206d63e84d1db8d957370737ba0e98467ea0ce274c66199901eaec18a08525715f53bfdb0aacb613d342ebdceeddc3b", + "b403d3691c03b0d3418df327d5860d34bbfcc4519bfbce36bf33b208385fadb9186bc78a76c489d89fd57e7dc75412d23bcd1dae8470ce9274754bb8585b13c5", + "31fc79738b8772b3f55cd8178813b3b52d0db5a419d30ba9495c4b9da0219fac6df8e7c23a811551a62b827f256ecdb8124ac8a6792ccfecc3b3012722e94463", + "bb2039ec287091bcc9642fc90049e73732e02e577e2862b32216ae9bedcd730c4c284ef3968c368b7d37584f97bd4b4dc6ef6127acfe2e6ae2509124e66c8af4", + "f53d68d13f45edfcb9bd415e2831e938350d5380d3432278fc1c0c381fcb7c65c82dafe051d8c8b0d44e0974a0e59ec7bf7ed0459f86e96f329fc79752510fd3", + "8d568c7984f0ecdf7640fbc483b5d8c9f86634f6f43291841b309a350ab9c1137d24066b09da9944bac54d5bb6580d836047aac74ab724b887ebf93d4b32eca9", + "c0b65ce5a96ff774c456cac3b5f2c4cd359b4ff53ef93a3da0778be4900d1e8da1601e769e8f1b02d2a2f8c5b9fa10b44f1c186985468feeb008730283a6657d", + "4900bba6f5fb103ece8ec96ada13a5c3c85488e05551da6b6b33d988e611ec0fe2e3c2aa48ea6ae8986a3a231b223c5d27cec2eadde91ce07981ee652862d1e4", + "c7f5c37c7285f927f76443414d4357ff789647d7a005a5a787e03c346b57f49f21b64fa9cf4b7e45573e23049017567121a9c3d4b2b73ec5e9413577525db45a", + "ec7096330736fdb2d64b5653e7475da746c23a4613a82687a28062d3236364284ac01720ffb406cfe265c0df626a188c9e5963ace5d3d5bb363e32c38c2190a6", + "82e744c75f4649ec52b80771a77d475a3bc091989556960e276a5f9ead92a03f718742cdcfeaee5cb85c44af198adc43a4a428f5f0c2ddb0be36059f06d7df73", + "2834b7a7170f1f5b68559ab78c1050ec21c919740b784a9072f6e5d69f828d70c919c5039fb148e39e2c8a52118378b064ca8d5001cd10a5478387b966715ed6", + "16b4ada883f72f853bb7ef253efcab0c3e2161687ad61543a0d2824f91c1f81347d86be709b16996e17f2dd486927b0288ad38d13063c4a9672c39397d3789b6", + "78d048f3a69d8b54ae0ed63a573ae350d89f7c6cf1f3688930de899afa037697629b314e5cd303aa62feea72a25bf42b304b6c6bcb27fae21c16d925e1fbdac3", + "0f746a48749287ada77a82961f05a4da4abdb7d77b1220f836d09ec814359c0ec0239b8c7b9ff9e02f569d1b301ef67c4612d1de4f730f81c12c40cc063c5caa", + "f0fc859d3bd195fbdc2d591e4cdac15179ec0f1dc821c11df1f0c1d26e6260aaa65b79fafacafd7d3ad61e600f250905f5878c87452897647a35b995bcadc3a3", + "2620f687e8625f6a412460b42e2cef67634208ce10a0cbd4dff7044a41b7880077e9f8dc3b8d1216d3376a21e015b58fb279b521d83f9388c7382c8505590b9b", + "227e3aed8d2cb10b918fcb04f9de3e6d0a57e08476d93759cd7b2ed54a1cbf0239c528fb04bbf288253e601d3bc38b21794afef90b17094a182cac557745e75f", + "1a929901b09c25f27d6b35be7b2f1c4745131fdebca7f3e2451926720434e0db6e74fd693ad29b777dc3355c592a361c4873b01133a57c2e3b7075cbdb86f4fc", + "5fd7968bc2fe34f220b5e3dc5af9571742d73b7d60819f2888b629072b96a9d8ab2d91b82d0a9aaba61bbd39958132fcc4257023d1eca591b3054e2dc81c8200", + "dfcce8cf32870cc6a503eadafc87fd6f78918b9b4d0737db6810be996b5497e7e5cc80e312f61e71ff3e9624436073156403f735f56b0b01845c18f6caf772e6", + "02f7ef3a9ce0fff960f67032b296efca3061f4934d690749f2d01c35c81c14f39a67fa350bc8a0359bf1724bffc3bca6d7c7bba4791fd522a3ad353c02ec5aa8", + "64be5c6aba65d594844ae78bb022e5bebe127fd6b6ffa5a13703855ab63b624dcd1a363f99203f632ec386f3ea767fc992e8ed9686586aa27555a8599d5b808f", + "f78585505c4eaa54a8b5be70a61e735e0ff97af944ddb3001e35d86c4e2199d976104b6ae31750a36a726ed285064f5981b503889fef822fcdc2898dddb7889a", + "e4b5566033869572edfd87479a5bb73c80e8759b91232879d96b1dda36c012076ee5a2ed7ae2de63ef8406a06aea82c188031b560beafb583fb3de9e57952a7e", + "e1b3e7ed867f6c9484a2a97f7715f25e25294e992e41f6a7c161ffc2adc6daaeb7113102d5e6090287fe6ad94ce5d6b739c6ca240b05c76fb73f25dd024bf935", + "85fd085fdc12a080983df07bd7012b0d402a0f4043fcb2775adf0bad174f9b08d1676e476985785c0a5dcc41dbff6d95ef4d66a3fbdc4a74b82ba52da0512b74", + "aed8fa764b0fbff821e05233d2f7b0900ec44d826f95e93c343c1bc3ba5a24374b1d616e7e7aba453a0ada5e4fab5382409e0d42ce9c2bc7fb39a99c340c20f0", + "7ba3b2e297233522eeb343bd3ebcfd835a04007735e87f0ca300cbee6d416565162171581e4020ff4cf176450f1291ea2285cb9ebffe4c56660627685145051c", + "de748bcf89ec88084721e16b85f30adb1a6134d664b5843569babc5bbd1a15ca9b61803c901a4fef32965a1749c9f3a4e243e173939dc5a8dc495c671ab52145", + "aaf4d2bdf200a919706d9842dce16c98140d34bc433df320aba9bd429e549aa7a3397652a4d768277786cf993cde2338673ed2e6b66c961fefb82cd20c93338f", + "c408218968b788bf864f0997e6bc4c3dba68b276e2125a4843296052ff93bf5767b8cdce7131f0876430c1165fec6c4f47adaa4fd8bcfacef463b5d3d0fa61a0", + "76d2d819c92bce55fa8e092ab1bf9b9eab237a25267986cacf2b8ee14d214d730dc9a5aa2d7b596e86a1fd8fa0804c77402d2fcd45083688b218b1cdfa0dcbcb", + "72065ee4dd91c2d8509fa1fc28a37c7fc9fa7d5b3f8ad3d0d7a25626b57b1b44788d4caf806290425f9890a3a2a35a905ab4b37acfd0da6e4517b2525c9651e4", + "64475dfe7600d7171bea0b394e27c9b00d8e74dd1e416a79473682ad3dfdbb706631558055cfc8a40e07bd015a4540dcdea15883cbbf31412df1de1cd4152b91", + "12cd1674a4488a5d7c2b3160d2e2c4b58371bedad793418d6f19c6ee385d70b3e06739369d4df910edb0b0a54cbff43d54544cd37ab3a06cfa0a3ddac8b66c89", + "60756966479dedc6dd4bcff8ea7d1d4ce4d4af2e7b097e32e3763518441147cc12b3c0ee6d2ecabf1198cec92e86a3616fba4f4e872f5825330adbb4c1dee444", + "a7803bcb71bc1d0f4383dde1e0612e04f872b715ad30815c2249cf34abb8b024915cb2fc9f4e7cc4c8cfd45be2d5a91eab0941c7d270e2da4ca4a9f7ac68663a", + "b84ef6a7229a34a750d9a98ee2529871816b87fbe3bc45b45fa5ae82d5141540211165c3c5d7a7476ba5a4aa06d66476f0d9dc49a3f1ee72c3acabd498967414", + "fae4b6d8efc3f8c8e64d001dabec3a21f544e82714745251b2b4b393f2f43e0da3d403c64db95a2cb6e23ebb7b9e94cdd5ddac54f07c4a61bd3cb10aa6f93b49", + "34f7286605a122369540141ded79b8957255da2d4155abbf5a8dbb89c8eb7ede8eeef1daa46dc29d751d045dc3b1d658bb64b80ff8589eddb3824b13da235a6b", + "3b3b48434be27b9eababba43bf6b35f14b30f6a88dc2e750c358470d6b3aa3c18e47db4017fa55106d8252f016371a00f5f8b070b74ba5f23cffc5511c9f09f0", + "ba289ebd6562c48c3e10a8ad6ce02e73433d1e93d7c9279d4d60a7e879ee11f441a000f48ed9f7c4ed87a45136d7dccdca482109c78a51062b3ba4044ada2469", + "022939e2386c5a37049856c850a2bb10a13dfea4212b4c732a8840a9ffa5faf54875c5448816b2785a007da8a8d2bc7d71a54e4e6571f10b600cbdb25d13ede3", + "e6fec19d89ce8717b1a087024670fe026f6c7cbda11caef959bb2d351bf856f8055d1c0ebdaaa9d1b17886fc2c562b5e99642fc064710c0d3488a02b5ed7f6fd", + "94c96f02a8f576aca32ba61c2b206f907285d9299b83ac175c209a8d43d53bfe683dd1d83e7549cb906c28f59ab7c46f8751366a28c39dd5fe2693c9019666c8", + "31a0cd215ebd2cb61de5b9edc91e6195e31c59a5648d5c9f737e125b2605708f2e325ab3381c8dce1a3e958886f1ecdc60318f882cfe20a24191352e617b0f21", + "91ab504a522dce78779f4c6c6ba2e6b6db5565c76d3e7e7c920caf7f757ef9db7c8fcf10e57f03379ea9bf75eb59895d96e149800b6aae01db778bb90afbc989", + "d85cabc6bd5b1a01a5afd8c6734740da9fd1c1acc6db29bfc8a2e5b668b028b6b3154bfb8703fa3180251d589ad38040ceb707c4bad1b5343cb426b61eaa49c1", + "d62efbec2ca9c1f8bd66ce8b3f6a898cb3f7566ba6568c618ad1feb2b65b76c3ce1dd20f7395372faf28427f61c9278049cf0140df434f5633048c86b81e0399", + "7c8fdc6175439e2c3db15bafa7fb06143a6a23bc90f449e79deef73c3d492a671715c193b6fea9f036050b946069856b897e08c00768f5ee5ddcf70b7cd6d0e0", + "58602ee7468e6bc9df21bd51b23c005f72d6cb013f0a1b48cbec5eca299299f97f09f54a9a01483eaeb315a6478bad37ba47ca1347c7c8fc9e6695592c91d723", + "27f5b79ed256b050993d793496edf4807c1d85a7b0a67c9c4fa99860750b0ae66989670a8ffd7856d7ce411599e58c4d77b232a62bef64d15275be46a68235ff", + "3957a976b9f1887bf004a8dca942c92d2b37ea52600f25e0c9bc5707d0279c00c6e85a839b0d2d8eb59c51d94788ebe62474a791cadf52cccf20f5070b6573fc", + "eaa2376d55380bf772ecca9cb0aa4668c95c707162fa86d518c8ce0ca9bf7362b9f2a0adc3ff59922df921b94567e81e452f6c1a07fc817cebe99604b3505d38", + "c1e2c78b6b2734e2480ec550434cb5d613111adcc21d475545c3b1b7e6ff12444476e5c055132e2229dc0f807044bb919b1a5662dd38a9ee65e243a3911aed1a", + "8ab48713389dd0fcf9f965d3ce66b1e559a1f8c58741d67683cd971354f452e62d0207a65e436c5d5d8f8ee71c6abfe50e669004c302b31a7ea8311d4a916051", + "24ce0addaa4c65038bd1b1c0f1452a0b128777aabc94a29df2fd6c7e2f85f8ab9ac7eff516b0e0a825c84a24cfe492eaad0a6308e46dd42fe8333ab971bb30ca", + "5154f929ee03045b6b0c0004fa778edee1d139893267cc84825ad7b36c63de32798e4a166d24686561354f63b00709a1364b3c241de3febf0754045897467cd4", + "e74e907920fd87bd5ad636dd11085e50ee70459c443e1ce5809af2bc2eba39f9e6d7128e0e3712c316da06f4705d78a4838e28121d4344a2c79c5e0db307a677", + "bf91a22334bac20f3fd80663b3cd06c4e8802f30e6b59f90d3035cc9798a217ed5a31abbda7fa6842827bdf2a7a1c21f6fcfccbb54c6c52926f32da816269be1", + "d9d5c74be5121b0bd742f26bffb8c89f89171f3f934913492b0903c271bbe2b3395ef259669bef43b57f7fcc3027db01823f6baee66e4f9fead4d6726c741fce", + "50c8b8cf34cd879f80e2faab3230b0c0e1cc3e9dcadeb1b9d97ab923415dd9a1fe38addd5c11756c67990b256e95ad6d8f9fedce10bf1c90679cde0ecf1be347", + "0a386e7cd5dd9b77a035e09fe6fee2c8ce61b5383c87ea43205059c5e4cd4f4408319bb0a82360f6a58e6c9ce3f487c446063bf813bc6ba535e17fc1826cfc91", + "1f1459cb6b61cbac5f0efe8fc487538f42548987fcd56221cfa7beb22504769e792c45adfb1d6b3d60d7b749c8a75b0bdf14e8ea721b95dca538ca6e25711209", + "e58b3836b7d8fedbb50ca5725c6571e74c0785e97821dab8b6298c10e4c079d4a6cdf22f0fedb55032925c16748115f01a105e77e00cee3d07924dc0d8f90659", + "b929cc6505f020158672deda56d0db081a2ee34c00c1100029bdf8ea98034fa4bf3e8655ec697fe36f40553c5bb46801644a627d3342f4fc92b61f03290fb381", + "72d353994b49d3e03153929a1e4d4f188ee58ab9e72ee8e512f29bc773913819ce057ddd7002c0433ee0a16114e3d156dd2c4a7e80ee53378b8670f23e33ef56", + "c70ef9bfd775d408176737a0736d68517ce1aaad7e81a93c8c1ed967ea214f56c8a377b1763e676615b60f3988241eae6eab9685a5124929d28188f29eab06f7", + "c230f0802679cb33822ef8b3b21bf7a9a28942092901d7dac3760300831026cf354c9232df3e084d9903130c601f63c1f4a4a4b8106e468cd443bbe5a734f45f", + "6f43094cafb5ebf1f7a4937ec50f56a4c9da303cbb55ac1f27f1f1976cd96beda9464f0e7b9c54620b8a9fba983164b8be3578425a024f5fe199c36356b88972", + "3745273f4c38225db2337381871a0c6aafd3af9b018c88aa02025850a5dc3a42a1a3e03e56cbf1b0876d63a441f1d2856a39b8801eb5af325201c415d65e97fe", + "c50c44cca3ec3edaae779a7e179450ebdda2f97067c690aa6c5a4ac7c30139bb27c0df4db3220e63cb110d64f37ffe078db72653e2daacf93ae3f0a2d1a7eb2e", + "8aef263e385cbc61e19b28914243262af5afe8726af3ce39a79c27028cf3ecd3f8d2dfd9cfc9ad91b58f6f20778fd5f02894a3d91c7d57d1e4b866a7f364b6be", + "28696141de6e2d9bcb3235578a66166c1448d3e905a1b482d423be4bc5369bc8c74dae0acc9cc123e1d8ddce9f97917e8c019c552da32d39d2219b9abf0fa8c8", + "2fb9eb2085830181903a9dafe3db428ee15be7662224efd643371fb25646aee716e531eca69b2bdc8233f1a8081fa43da1500302975a77f42fa592136710e9dc", + "66f9a7143f7a3314a669bf2e24bbb35014261d639f495b6c9c1f104fe8e320aca60d4550d69d52edbd5a3cdeb4014ae65b1d87aa770b69ae5c15f4330b0b0ad8", + "f4c4dd1d594c3565e3e25ca43dad82f62abea4835ed4cd811bcd975e46279828d44d4c62c3679f1b7f7b9dd4571d7b49557347b8c5460cbdc1bef690fb2a08c0", + "8f1dc9649c3a84551f8f6e91cac68242a43b1f8f328ee92280257387fa7559aa6db12e4aeadc2d26099178749c6864b357f3f83b2fb3efa8d2a8db056bed6bcc", + "3139c1a7f97afd1675d460ebbc07f2728aa150df849624511ee04b743ba0a833092f18c12dc91b4dd243f333402f59fe28abdbbbae301e7b659c7a26d5c0f979", + "06f94a2996158a819fe34c40de3cf0379fd9fb85b3e363ba3926a0e7d960e3f4c2e0c70c7ce0ccb2a64fc29869f6e7ab12bd4d3f14fce943279027e785fb5c29", + "c29c399ef3eee8961e87565c1ce263925fc3d0ce267d13e48dd9e732ee67b0f69fad56401b0f10fcaac119201046cca28c5b14abdea3212ae65562f7f138db3d", + "4cec4c9df52eef05c3f6faaa9791bc7445937183224ecc37a1e58d0132d35617531d7e795f52af7b1eb9d147de1292d345fe341823f8e6bc1e5badca5c656108", + "898bfbae93b3e18d00697eab7d9704fa36ec339d076131cefdf30edbe8d9cc81c3a80b129659b163a323bab9793d4feed92d54dae966c77529764a09be88db45", + "ee9bd0469d3aaf4f14035be48a2c3b84d9b4b1fff1d945e1f1c1d38980a951be197b25fe22c731f20aeacc930ba9c4a1f4762227617ad350fdabb4e80273a0f4", + "3d4d3113300581cd96acbf091c3d0f3c310138cd6979e6026cde623e2dd1b24d4a8638bed1073344783ad0649cc6305ccec04beb49f31c633088a99b65130267", + "95c0591ad91f921ac7be6d9ce37e0663ed8011c1cfd6d0162a5572e94368bac02024485e6a39854aa46fe38e97d6c6b1947cd272d86b06bb5b2f78b9b68d559d", + "227b79ded368153bf46c0a3ca978bfdbef31f3024a5665842468490b0ff748ae04e7832ed4c9f49de9b1706709d623e5c8c15e3caecae8d5e433430ff72f20eb", + "5d34f3952f0105eef88ae8b64c6ce95ebfade0e02c69b08762a8712d2e4911ad3f941fc4034dc9b2e479fdbcd279b902faf5d838bb2e0c6495d372b5b7029813", + "7f939bf8353abce49e77f14f3750af20b7b03902e1a1e7fb6aaf76d0259cd401a83190f15640e74f3e6c5a90e839c7821f6474757f75c7bf9002084ddc7a62dc", + "062b61a2f9a33a71d7d0a06119644c70b0716a504de7e5e1be49bd7b86e7ed6817714f9f0fc313d06129597e9a2235ec8521de36f7290a90ccfc1ffa6d0aee29", + "f29e01eeae64311eb7f1c6422f946bf7bea36379523e7b2bbaba7d1d34a22d5ea5f1c5a09d5ce1fe682cced9a4798d1a05b46cd72dff5c1b355440b2a2d476bc", + "ec38cd3bbab3ef35d7cb6d5c914298351d8a9dc97fcee051a8a02f58e3ed6184d0b7810a5615411ab1b95209c3c810114fdeb22452084e77f3f847c6dbaafe16", + "c2aef5e0ca43e82641565b8cb943aa8ba53550caef793b6532fafad94b816082f0113a3ea2f63608ab40437ecc0f0229cb8fa224dcf1c478a67d9b64162b92d1", + "15f534efff7105cd1c254d074e27d5898b89313b7d366dc2d7d87113fa7d53aae13f6dba487ad8103d5e854c91fdb6e1e74b2ef6d1431769c30767dde067a35c", + "89acbca0b169897a0a2714c2df8c95b5b79cb69390142b7d6018bb3e3076b099b79a964152a9d912b1b86412b7e372e9cecad7f25d4cbab8a317be36492a67d7", + "e3c0739190ed849c9c962fd9dbb55e207e624fcac1eb417691515499eea8d8267b7e8f1287a63633af5011fde8c4ddf55bfdf722edf88831414f2cfaed59cb9a", + "8d6cf87c08380d2d1506eee46fd4222d21d8c04e585fbfd08269c98f702833a156326a0724656400ee09351d57b440175e2a5de93cc5f80db6daf83576cf75fa", + "da24bede383666d563eeed37f6319baf20d5c75d1635a6ba5ef4cfa1ac95487e96f8c08af600aab87c986ebad49fc70a58b4890b9c876e091016daf49e1d322e", + "f9d1d1b1e87ea7ae753a029750cc1cf3d0157d41805e245c5617bb934e732f0ae3180b78e05bfe76c7c3051e3e3ac78b9b50c05142657e1e03215d6ec7bfd0fc", + "11b7bc1668032048aa43343de476395e814bbbc223678db951a1b03a021efac948cfbe215f97fe9a72a2f6bc039e3956bfa417c1a9f10d6d7ba5d3d32ff323e5", + "b8d9000e4fc2b066edb91afee8e7eb0f24e3a201db8b6793c0608581e628ed0bcc4e5aa6787992a4bcc44e288093e63ee83abd0bc3ec6d0934a674a4da13838a", + "ce325e294f9b6719d6b61278276ae06a2564c03bb0b783fafe785bdf89c7d5acd83e78756d301b445699024eaeb77b54d477336ec2a4f332f2b3f88765ddb0c3", + "29acc30e9603ae2fccf90bf97e6cc463ebe28c1b2f9b4b765e70537c25c702a29dcbfbf14c99c54345ba2b51f17b77b5f15db92bbad8fa95c471f5d070a137cc", + "3379cbaae562a87b4c0425550ffdd6bfe1203f0d666cc7ea095be407a5dfe61ee91441cd5154b3e53b4f5fb31ad4c7a9ad5c7af4ae679aa51a54003a54ca6b2d", + "3095a349d245708c7cf550118703d7302c27b60af5d4e67fc978f8a4e60953c7a04f92fcf41aee64321ccb707a895851552b1e37b00bc5e6b72fa5bcef9e3fff", + "07262d738b09321f4dbccec4bb26f48cb0f0ed246ce0b31b9a6e7bc683049f1f3e5545f28ce932dd985c5ab0f43bd6de0770560af329065ed2e49d34624c2cbb", + "b6405eca8ee3316c87061cc6ec18dba53e6c250c63ba1f3bae9e55dd3498036af08cd272aa24d713c6020d77ab2f3919af1a32f307420618ab97e73953994fb4", + "7ee682f63148ee45f6e5315da81e5c6e557c2c34641fc509c7a5701088c38a74756168e2cd8d351e88fd1a451f360a01f5b2580f9b5a2e8cfc138f3dd59a3ffc", + "1d263c179d6b268f6fa016f3a4f29e943891125ed8593c81256059f5a7b44af2dcb2030d175c00e62ecaf7ee96682aa07ab20a611024a28532b1c25b86657902", + "106d132cbdb4cd2597812846e2bc1bf732fec5f0a5f65dbb39ec4e6dc64ab2ce6d24630d0f15a805c3540025d84afa98e36703c3dbee713e72dde8465bc1be7e", + "0e79968226650667a8d862ea8da4891af56a4e3a8b6d1750e394f0dea76d640d85077bcec2cc86886e506751b4f6a5838f7f0b5fef765d9dc90dcdcbaf079f08", + "521156a82ab0c4e566e5844d5e31ad9aaf144bbd5a464fdca34dbd5717e8ff711d3ffebbfa085d67fe996a34f6d3e4e60b1396bf4b1610c263bdbb834d560816", + "1aba88befc55bc25efbce02db8b9933e46f57661baeabeb21cc2574d2a518a3cba5dc5a38e49713440b25f9c744e75f6b85c9d8f4681f676160f6105357b8406", + "5a9949fcb2c473cda968ac1b5d08566dc2d816d960f57e63b898fa701cf8ebd3f59b124d95bfbbedc5f1cf0e17d5eaed0c02c50b69d8a402cabcca4433b51fd4", + "b0cead09807c672af2eb2b0f06dde46cf5370e15a4096b1a7d7cbb36ec31c205fbefca00b7a4162fa89fb4fb3eb78d79770c23f44e7206664ce3cd931c291e5d", + "bb6664931ec97044e45b2ae420ae1c551a8874bc937d08e969399c3964ebdba8346cdd5d09caafe4c28ba7ec788191ceca65ddd6f95f18583e040d0f30d0364d", + "65bc770a5faa3792369803683e844b0be7ee96f29f6d6a35568006bd5590f9a4ef639b7a8061c7b0424b66b60ac34af3119905f33a9d8c3ae18382ca9b689900", + "ea9b4dca333336aaf839a45c6eaa48b8cb4c7ddabffea4f643d6357ea6628a480a5b45f2b052c1b07d1fedca918b6f1139d80f74c24510dcbaa4be70eacc1b06", + "e6342fb4a780ad975d0e24bce149989b91d360557e87994f6b457b895575cc02d0c15bad3ce7577f4c63927ff13f3e381ff7e72bdbe745324844a9d27e3f1c01", + "3e209c9b33e8e461178ab46b1c64b49a07fb745f1c8bc95fbfb94c6b87c69516651b264ef980937fad41238b91ddc011a5dd777c7efd4494b4b6ecd3a9c22ac0", + "fd6a3d5b1875d80486d6e69694a56dbb04a99a4d051f15db2689776ba1c4882e6d462a603b7015dc9f4b7450f05394303b8652cfb404a266962c41bae6e18a94", + "951e27517e6bad9e4195fc8671dee3e7e9be69cee1422cb9fecfce0dba875f7b310b93ee3a3d558f941f635f668ff832d2c1d033c5e2f0997e4c66f147344e02", + "8eba2f874f1ae84041903c7c4253c82292530fc8509550bfdc34c95c7e2889d5650b0ad8cb988e5c4894cb87fbfbb19612ea93ccc4c5cad17158b9763464b492", + "16f712eaa1b7c6354719a8e7dbdfaf55e4063a4d277d947550019b38dfb564830911057d50506136e2394c3b28945cc964967d54e3000c2181626cfb9b73efd2", + "c39639e7d5c7fb8cdd0fd3e6a52096039437122f21c78f1679cea9d78a734c56ecbeb28654b4f18e342c331f6f7229ec4b4bc281b2d80a6eb50043f31796c88c", + "72d081af99f8a173dcc9a0ac4eb3557405639a29084b54a40172912a2f8a395129d5536f0918e902f9e8fa6000995f4168ddc5f893011be6a0dbc9b8a1a3f5bb", + "c11aa81e5efd24d5fc27ee586cfd8847fbb0e27601ccece5ecca0198e3c7765393bb74457c7e7a27eb9170350e1fb53857177506be3e762cc0f14d8c3afe9077", + "c28f2150b452e6c0c424bcde6f8d72007f9310fed7f2f87de0dbb64f4479d6c1441ba66f44b2accee61609177ed340128b407ecec7c64bbe50d63d22d8627727", + "f63d88122877ec30b8c8b00d22e89000a966426112bd44166e2f525b769ccbe9b286d437a0129130dde1a86c43e04bedb594e671d98283afe64ce331de9828fd", + "348b0532880b88a6614a8d7408c3f913357fbb60e995c60205be9139e74998aede7f4581e42f6b52698f7fa1219708c14498067fd1e09502de83a77dd281150c", + "5133dc8bef725359dff59792d85eaf75b7e1dcd1978b01c35b1b85fcebc63388ad99a17b6346a217dc1a9622ebd122ecf6913c4d31a6b52a695b86af00d741a0", + "2753c4c0e98ecad806e88780ec27fccd0f5c1ab547f9e4bf1659d192c23aa2cc971b58b6802580baef8adc3b776ef7086b2545c2987f348ee3719cdef258c403", + "b1663573ce4b9d8caefc865012f3e39714b9898a5da6ce17c25a6a47931a9ddb9bbe98adaa553beed436e89578455416c2a52a525cf2862b8d1d49a2531b7391", + "64f58bd6bfc856f5e873b2a2956ea0eda0d6db0da39c8c7fc67c9f9feefcff3072cdf9e6ea37f69a44f0c61aa0da3693c2db5b54960c0281a088151db42b11e8", + "0764c7be28125d9065c4b98a69d60aede703547c66a12e17e1c618994132f5ef82482c1e3fe3146cc65376cc109f0138ed9a80e49f1f3c7d610d2f2432f20605", + "f748784398a2ff03ebeb07e155e66116a839741a336e32da71ec696001f0ad1b25cd48c69cfca7265eca1dd71904a0ce748ac4124f3571076dfa7116a9cf00e9", + "3f0dbc0186bceb6b785ba78d2a2a013c910be157bdaffae81bb6663b1a73722f7f1228795f3ecada87cf6ef0078474af73f31eca0cc200ed975b6893f761cb6d", + "d4762cd4599876ca75b2b8fe249944dbd27ace741fdab93616cbc6e425460feb51d4e7adcc38180e7fc47c89024a7f56191adb878dfde4ead62223f5a2610efe", + "cd36b3d5b4c91b90fcbba79513cfee1907d8645a162afd0cd4cf4192d4a5f4c892183a8eacdb2b6b6a9d9aa8c11ac1b261b380dbee24ca468f1bfd043c58eefe", + "98593452281661a53c48a9d8cd790826c1a1ce567738053d0bee4a91a3d5bd92eefdbabebe3204f2031ca5f781bda99ef5d8ae56e5b04a9e1ecd21b0eb05d3e1", + "771f57dd2775ccdab55921d3e8e30ccf484d61fe1c1b9c2ae819d0fb2a12fab9be70c4a7a138da84e8280435daade5bbe66af0836a154f817fb17f3397e725a3", + "c60897c6f828e21f16fbb5f15b323f87b6c8955eabf1d38061f707f608abdd993fac3070633e286cf8339ce295dd352df4b4b40b2f29da1dd50b3a05d079e6bb", + "8210cd2c2d3b135c2cf07fa0d1433cd771f325d075c6469d9c7f1ba0943cd4ab09808cabf4acb9ce5bb88b498929b4b847f681ad2c490d042db2aec94214b06b", + "1d4edfffd8fd80f7e4107840fa3aa31e32598491e4af7013c197a65b7f36dd3ac4b478456111cd4309d9243510782fa31b7c4c95fa951520d020eb7e5c36e4ef", + "af8e6e91fab46ce4873e1a50a8ef448cc29121f7f74deef34a71ef89cc00d9274bc6c2454bbb3230d8b2ec94c62b1dec85f3593bfa30ea6f7a44d7c09465a253", + "29fd384ed4906f2d13aa9fe7af905990938bed807f1832454a372ab412eea1f5625a1fcc9ac8343b7c67c5aba6e0b1cc4644654913692c6b39eb9187ceacd3ec", + "a268c7885d9874a51c44dffed8ea53e94f78456e0b2ed99ff5a3924760813826d960a15edbedbb5de5226ba4b074e71b05c55b9756bb79e55c02754c2c7b6c8a", + "0cf8545488d56a86817cd7ecb10f7116b7ea530a45b6ea497b6c72c997e09e3d0da8698f46bb006fc977c2cd3d1177463ac9057fdd1662c85d0c126443c10473", + "b39614268fdd8781515e2cfebf89b4d5402bab10c226e6344e6b9ae000fb0d6c79cb2f3ec80e80eaeb1980d2f8698916bd2e9f747236655116649cd3ca23a837", + "74bef092fc6f1e5dba3663a3fb003b2a5ba257496536d99f62b9d73f8f9eb3ce9ff3eec709eb883655ec9eb896b9128f2afc89cf7d1ab58a72f4a3bf034d2b4a", + "3a988d38d75611f3ef38b8774980b33e573b6c57bee0469ba5eed9b44f29945e7347967fba2c162e1c3be7f310f2f75ee2381e7bfd6b3f0baea8d95dfb1dafb1", + "58aedfce6f67ddc85a28c992f1c0bd0969f041e66f1ee88020a125cbfcfebcd61709c9c4eba192c15e69f020d462486019fa8dea0cd7a42921a19d2fe546d43d", + "9347bd291473e6b4e368437b8e561e065f649a6d8ada479ad09b1999a8f26b91cf6120fd3bfe014e83f23acfa4c0ad7b3712b2c3c0733270663112ccd9285cd9", + "b32163e7c5dbb5f51fdc11d2eac875efbbcb7e7699090a7e7ff8a8d50795af5d74d9ff98543ef8cdf89ac13d0485278756e0ef00c817745661e1d59fe38e7537", + "1085d78307b1c4b008c57a2e7e5b234658a0a82e4ff1e4aaac72b312fda0fe27d233bc5b10e9cc17fdc7697b540c7d95eb215a19a1a0e20e1abfa126efd568c7", + "4e5c734c7dde011d83eac2b7347b373594f92d7091b9ca34cb9c6f39bdf5a8d2f134379e16d822f6522170ccf2ddd55c84b9e6c64fc927ac4cf8dfb2a17701f2", + "695d83bd990a1117b3d0ce06cc888027d12a054c2677fd82f0d4fbfc93575523e7991a5e35a3752e9b70ce62992e268a877744cdd435f5f130869c9a2074b338", + "a6213743568e3b3158b9184301f3690847554c68457cb40fc9a4b8cfd8d4a118c301a07737aeda0f929c68913c5f51c80394f53bff1c3e83b2e40ca97eba9e15", + "d444bfa2362a96df213d070e33fa841f51334e4e76866b8139e8af3bb3398be2dfaddcbc56b9146de9f68118dc5829e74b0c28d7711907b121f9161cb92b69a9", + "142709d62e28fcccd0af97fad0f8465b971e82201dc51070faa0372aa43e92484be1c1e73ba10906d5d1853db6a4106e0a7bf9800d373d6dee2d46d62ef2a461", +} diff --git a/contrib/backends/nntpchand/src/vendor/github.com/dchest/blake2b/block.go b/contrib/backends/nntpchand/src/vendor/github.com/dchest/blake2b/block.go new file mode 100644 index 0000000..2f04bb7 --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/dchest/blake2b/block.go @@ -0,0 +1,1420 @@ +// Written in 2012 by Dmitry Chestnykh. +// +// To the extent possible under law, the author have dedicated all copyright +// and related and neighboring rights to this software to the public domain +// worldwide. This software is distributed without any warranty. +// http://creativecommons.org/publicdomain/zero/1.0/ + +// BLAKE2b compression of message blocks. + +package blake2b + +func blocks(d *digest, p []uint8) { + h0, h1, h2, h3, h4, h5, h6, h7 := d.h[0], d.h[1], d.h[2], d.h[3], d.h[4], d.h[5], d.h[6], d.h[7] + + for len(p) >= BlockSize { + // Increment counter. + d.t[0] += BlockSize + if d.t[0] < BlockSize { + d.t[1]++ + } + // Initialize compression function. + v0, v1, v2, v3, v4, v5, v6, v7 := h0, h1, h2, h3, h4, h5, h6, h7 + v8 := iv[0] + v9 := iv[1] + v10 := iv[2] + v11 := iv[3] + v12 := iv[4] ^ d.t[0] + v13 := iv[5] ^ d.t[1] + v14 := iv[6] ^ d.f[0] + v15 := iv[7] ^ d.f[1] + var m [16]uint64 + + j := 0 + for i := 0; i < 16; i++ { + m[i] = uint64(p[j]) | uint64(p[j+1])<<8 | uint64(p[j+2])<<16 | uint64(p[j+3])<<24 | + uint64(p[j+4])<<32 | uint64(p[j+5])<<40 | uint64(p[j+6])<<48 | uint64(p[j+7])<<56 + j += 8 + } + + // Round 1. + v0 += m[0] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-32) | v12>>32 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-24) | v4>>24 + v1 += m[2] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-32) | v13>>32 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-24) | v5>>24 + v2 += m[4] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-32) | v14>>32 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-24) | v6>>24 + v3 += m[6] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-32) | v15>>32 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-24) | v7>>24 + v2 += m[5] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-16) | v14>>16 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-63) | v6>>63 + v3 += m[7] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-16) | v15>>16 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-63) | v7>>63 + v1 += m[3] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-16) | v13>>16 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-63) | v5>>63 + v0 += m[1] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-16) | v12>>16 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-63) | v4>>63 + v0 += m[8] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-32) | v15>>32 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-24) | v5>>24 + v1 += m[10] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-32) | v12>>32 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-24) | v6>>24 + v2 += m[12] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-32) | v13>>32 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-24) | v7>>24 + v3 += m[14] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-32) | v14>>32 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-24) | v4>>24 + v2 += m[13] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-16) | v13>>16 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-63) | v7>>63 + v3 += m[15] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-16) | v14>>16 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-63) | v4>>63 + v1 += m[11] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-16) | v12>>16 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-63) | v6>>63 + v0 += m[9] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-16) | v15>>16 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-63) | v5>>63 + + // Round 2. + v0 += m[14] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-32) | v12>>32 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-24) | v4>>24 + v1 += m[4] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-32) | v13>>32 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-24) | v5>>24 + v2 += m[9] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-32) | v14>>32 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-24) | v6>>24 + v3 += m[13] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-32) | v15>>32 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-24) | v7>>24 + v2 += m[15] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-16) | v14>>16 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-63) | v6>>63 + v3 += m[6] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-16) | v15>>16 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-63) | v7>>63 + v1 += m[8] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-16) | v13>>16 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-63) | v5>>63 + v0 += m[10] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-16) | v12>>16 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-63) | v4>>63 + v0 += m[1] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-32) | v15>>32 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-24) | v5>>24 + v1 += m[0] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-32) | v12>>32 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-24) | v6>>24 + v2 += m[11] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-32) | v13>>32 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-24) | v7>>24 + v3 += m[5] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-32) | v14>>32 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-24) | v4>>24 + v2 += m[7] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-16) | v13>>16 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-63) | v7>>63 + v3 += m[3] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-16) | v14>>16 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-63) | v4>>63 + v1 += m[2] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-16) | v12>>16 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-63) | v6>>63 + v0 += m[12] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-16) | v15>>16 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-63) | v5>>63 + + // Round 3. + v0 += m[11] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-32) | v12>>32 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-24) | v4>>24 + v1 += m[12] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-32) | v13>>32 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-24) | v5>>24 + v2 += m[5] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-32) | v14>>32 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-24) | v6>>24 + v3 += m[15] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-32) | v15>>32 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-24) | v7>>24 + v2 += m[2] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-16) | v14>>16 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-63) | v6>>63 + v3 += m[13] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-16) | v15>>16 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-63) | v7>>63 + v1 += m[0] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-16) | v13>>16 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-63) | v5>>63 + v0 += m[8] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-16) | v12>>16 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-63) | v4>>63 + v0 += m[10] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-32) | v15>>32 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-24) | v5>>24 + v1 += m[3] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-32) | v12>>32 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-24) | v6>>24 + v2 += m[7] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-32) | v13>>32 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-24) | v7>>24 + v3 += m[9] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-32) | v14>>32 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-24) | v4>>24 + v2 += m[1] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-16) | v13>>16 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-63) | v7>>63 + v3 += m[4] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-16) | v14>>16 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-63) | v4>>63 + v1 += m[6] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-16) | v12>>16 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-63) | v6>>63 + v0 += m[14] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-16) | v15>>16 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-63) | v5>>63 + + // Round 4. + v0 += m[7] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-32) | v12>>32 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-24) | v4>>24 + v1 += m[3] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-32) | v13>>32 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-24) | v5>>24 + v2 += m[13] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-32) | v14>>32 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-24) | v6>>24 + v3 += m[11] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-32) | v15>>32 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-24) | v7>>24 + v2 += m[12] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-16) | v14>>16 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-63) | v6>>63 + v3 += m[14] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-16) | v15>>16 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-63) | v7>>63 + v1 += m[1] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-16) | v13>>16 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-63) | v5>>63 + v0 += m[9] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-16) | v12>>16 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-63) | v4>>63 + v0 += m[2] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-32) | v15>>32 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-24) | v5>>24 + v1 += m[5] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-32) | v12>>32 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-24) | v6>>24 + v2 += m[4] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-32) | v13>>32 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-24) | v7>>24 + v3 += m[15] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-32) | v14>>32 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-24) | v4>>24 + v2 += m[0] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-16) | v13>>16 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-63) | v7>>63 + v3 += m[8] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-16) | v14>>16 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-63) | v4>>63 + v1 += m[10] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-16) | v12>>16 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-63) | v6>>63 + v0 += m[6] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-16) | v15>>16 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-63) | v5>>63 + + // Round 5. + v0 += m[9] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-32) | v12>>32 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-24) | v4>>24 + v1 += m[5] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-32) | v13>>32 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-24) | v5>>24 + v2 += m[2] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-32) | v14>>32 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-24) | v6>>24 + v3 += m[10] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-32) | v15>>32 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-24) | v7>>24 + v2 += m[4] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-16) | v14>>16 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-63) | v6>>63 + v3 += m[15] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-16) | v15>>16 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-63) | v7>>63 + v1 += m[7] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-16) | v13>>16 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-63) | v5>>63 + v0 += m[0] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-16) | v12>>16 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-63) | v4>>63 + v0 += m[14] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-32) | v15>>32 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-24) | v5>>24 + v1 += m[11] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-32) | v12>>32 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-24) | v6>>24 + v2 += m[6] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-32) | v13>>32 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-24) | v7>>24 + v3 += m[3] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-32) | v14>>32 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-24) | v4>>24 + v2 += m[8] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-16) | v13>>16 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-63) | v7>>63 + v3 += m[13] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-16) | v14>>16 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-63) | v4>>63 + v1 += m[12] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-16) | v12>>16 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-63) | v6>>63 + v0 += m[1] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-16) | v15>>16 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-63) | v5>>63 + + // Round 6. + v0 += m[2] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-32) | v12>>32 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-24) | v4>>24 + v1 += m[6] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-32) | v13>>32 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-24) | v5>>24 + v2 += m[0] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-32) | v14>>32 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-24) | v6>>24 + v3 += m[8] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-32) | v15>>32 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-24) | v7>>24 + v2 += m[11] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-16) | v14>>16 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-63) | v6>>63 + v3 += m[3] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-16) | v15>>16 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-63) | v7>>63 + v1 += m[10] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-16) | v13>>16 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-63) | v5>>63 + v0 += m[12] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-16) | v12>>16 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-63) | v4>>63 + v0 += m[4] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-32) | v15>>32 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-24) | v5>>24 + v1 += m[7] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-32) | v12>>32 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-24) | v6>>24 + v2 += m[15] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-32) | v13>>32 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-24) | v7>>24 + v3 += m[1] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-32) | v14>>32 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-24) | v4>>24 + v2 += m[14] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-16) | v13>>16 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-63) | v7>>63 + v3 += m[9] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-16) | v14>>16 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-63) | v4>>63 + v1 += m[5] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-16) | v12>>16 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-63) | v6>>63 + v0 += m[13] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-16) | v15>>16 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-63) | v5>>63 + + // Round 7. + v0 += m[12] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-32) | v12>>32 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-24) | v4>>24 + v1 += m[1] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-32) | v13>>32 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-24) | v5>>24 + v2 += m[14] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-32) | v14>>32 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-24) | v6>>24 + v3 += m[4] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-32) | v15>>32 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-24) | v7>>24 + v2 += m[13] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-16) | v14>>16 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-63) | v6>>63 + v3 += m[10] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-16) | v15>>16 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-63) | v7>>63 + v1 += m[15] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-16) | v13>>16 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-63) | v5>>63 + v0 += m[5] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-16) | v12>>16 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-63) | v4>>63 + v0 += m[0] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-32) | v15>>32 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-24) | v5>>24 + v1 += m[6] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-32) | v12>>32 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-24) | v6>>24 + v2 += m[9] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-32) | v13>>32 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-24) | v7>>24 + v3 += m[8] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-32) | v14>>32 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-24) | v4>>24 + v2 += m[2] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-16) | v13>>16 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-63) | v7>>63 + v3 += m[11] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-16) | v14>>16 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-63) | v4>>63 + v1 += m[3] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-16) | v12>>16 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-63) | v6>>63 + v0 += m[7] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-16) | v15>>16 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-63) | v5>>63 + + // Round 8. + v0 += m[13] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-32) | v12>>32 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-24) | v4>>24 + v1 += m[7] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-32) | v13>>32 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-24) | v5>>24 + v2 += m[12] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-32) | v14>>32 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-24) | v6>>24 + v3 += m[3] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-32) | v15>>32 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-24) | v7>>24 + v2 += m[1] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-16) | v14>>16 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-63) | v6>>63 + v3 += m[9] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-16) | v15>>16 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-63) | v7>>63 + v1 += m[14] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-16) | v13>>16 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-63) | v5>>63 + v0 += m[11] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-16) | v12>>16 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-63) | v4>>63 + v0 += m[5] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-32) | v15>>32 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-24) | v5>>24 + v1 += m[15] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-32) | v12>>32 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-24) | v6>>24 + v2 += m[8] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-32) | v13>>32 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-24) | v7>>24 + v3 += m[2] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-32) | v14>>32 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-24) | v4>>24 + v2 += m[6] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-16) | v13>>16 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-63) | v7>>63 + v3 += m[10] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-16) | v14>>16 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-63) | v4>>63 + v1 += m[4] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-16) | v12>>16 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-63) | v6>>63 + v0 += m[0] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-16) | v15>>16 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-63) | v5>>63 + + // Round 9. + v0 += m[6] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-32) | v12>>32 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-24) | v4>>24 + v1 += m[14] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-32) | v13>>32 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-24) | v5>>24 + v2 += m[11] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-32) | v14>>32 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-24) | v6>>24 + v3 += m[0] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-32) | v15>>32 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-24) | v7>>24 + v2 += m[3] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-16) | v14>>16 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-63) | v6>>63 + v3 += m[8] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-16) | v15>>16 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-63) | v7>>63 + v1 += m[9] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-16) | v13>>16 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-63) | v5>>63 + v0 += m[15] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-16) | v12>>16 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-63) | v4>>63 + v0 += m[12] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-32) | v15>>32 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-24) | v5>>24 + v1 += m[13] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-32) | v12>>32 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-24) | v6>>24 + v2 += m[1] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-32) | v13>>32 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-24) | v7>>24 + v3 += m[10] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-32) | v14>>32 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-24) | v4>>24 + v2 += m[4] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-16) | v13>>16 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-63) | v7>>63 + v3 += m[5] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-16) | v14>>16 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-63) | v4>>63 + v1 += m[7] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-16) | v12>>16 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-63) | v6>>63 + v0 += m[2] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-16) | v15>>16 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-63) | v5>>63 + + // Round 10. + v0 += m[10] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-32) | v12>>32 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-24) | v4>>24 + v1 += m[8] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-32) | v13>>32 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-24) | v5>>24 + v2 += m[7] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-32) | v14>>32 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-24) | v6>>24 + v3 += m[1] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-32) | v15>>32 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-24) | v7>>24 + v2 += m[6] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-16) | v14>>16 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-63) | v6>>63 + v3 += m[5] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-16) | v15>>16 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-63) | v7>>63 + v1 += m[4] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-16) | v13>>16 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-63) | v5>>63 + v0 += m[2] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-16) | v12>>16 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-63) | v4>>63 + v0 += m[15] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-32) | v15>>32 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-24) | v5>>24 + v1 += m[9] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-32) | v12>>32 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-24) | v6>>24 + v2 += m[3] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-32) | v13>>32 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-24) | v7>>24 + v3 += m[13] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-32) | v14>>32 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-24) | v4>>24 + v2 += m[12] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-16) | v13>>16 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-63) | v7>>63 + v3 += m[0] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-16) | v14>>16 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-63) | v4>>63 + v1 += m[14] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-16) | v12>>16 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-63) | v6>>63 + v0 += m[11] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-16) | v15>>16 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-63) | v5>>63 + + // Round 11. + v0 += m[0] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-32) | v12>>32 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-24) | v4>>24 + v1 += m[2] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-32) | v13>>32 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-24) | v5>>24 + v2 += m[4] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-32) | v14>>32 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-24) | v6>>24 + v3 += m[6] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-32) | v15>>32 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-24) | v7>>24 + v2 += m[5] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-16) | v14>>16 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-63) | v6>>63 + v3 += m[7] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-16) | v15>>16 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-63) | v7>>63 + v1 += m[3] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-16) | v13>>16 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-63) | v5>>63 + v0 += m[1] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-16) | v12>>16 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-63) | v4>>63 + v0 += m[8] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-32) | v15>>32 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-24) | v5>>24 + v1 += m[10] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-32) | v12>>32 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-24) | v6>>24 + v2 += m[12] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-32) | v13>>32 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-24) | v7>>24 + v3 += m[14] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-32) | v14>>32 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-24) | v4>>24 + v2 += m[13] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-16) | v13>>16 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-63) | v7>>63 + v3 += m[15] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-16) | v14>>16 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-63) | v4>>63 + v1 += m[11] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-16) | v12>>16 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-63) | v6>>63 + v0 += m[9] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-16) | v15>>16 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-63) | v5>>63 + + // Round 12. + v0 += m[14] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-32) | v12>>32 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-24) | v4>>24 + v1 += m[4] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-32) | v13>>32 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-24) | v5>>24 + v2 += m[9] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-32) | v14>>32 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-24) | v6>>24 + v3 += m[13] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-32) | v15>>32 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-24) | v7>>24 + v2 += m[15] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-16) | v14>>16 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-63) | v6>>63 + v3 += m[6] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-16) | v15>>16 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-63) | v7>>63 + v1 += m[8] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-16) | v13>>16 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-63) | v5>>63 + v0 += m[10] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-16) | v12>>16 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-63) | v4>>63 + v0 += m[1] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-32) | v15>>32 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-24) | v5>>24 + v1 += m[0] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-32) | v12>>32 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-24) | v6>>24 + v2 += m[11] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-32) | v13>>32 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-24) | v7>>24 + v3 += m[5] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-32) | v14>>32 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-24) | v4>>24 + v2 += m[7] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-16) | v13>>16 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-63) | v7>>63 + v3 += m[3] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-16) | v14>>16 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-63) | v4>>63 + v1 += m[2] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-16) | v12>>16 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-63) | v6>>63 + v0 += m[12] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-16) | v15>>16 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-63) | v5>>63 + + h0 ^= v0 ^ v8 + h1 ^= v1 ^ v9 + h2 ^= v2 ^ v10 + h3 ^= v3 ^ v11 + h4 ^= v4 ^ v12 + h5 ^= v5 ^ v13 + h6 ^= v6 ^ v14 + h7 ^= v7 ^ v15 + + p = p[BlockSize:] + } + d.h[0], d.h[1], d.h[2], d.h[3], d.h[4], d.h[5], d.h[6], d.h[7] = h0, h1, h2, h3, h4, h5, h6, h7 +} diff --git a/contrib/backends/nntpchand/src/vendor/github.com/dchest/captcha/.gitignore b/contrib/backends/nntpchand/src/vendor/github.com/dchest/captcha/.gitignore new file mode 100644 index 0000000..ea1cde5 --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/dchest/captcha/.gitignore @@ -0,0 +1,8 @@ +# Generated test captchas +capgen/*.png +capgen/*.wav + +# Programs +capgen/capgen +cangensounds/cangensounds +capexample/capexample diff --git a/contrib/backends/nntpchand/src/vendor/github.com/dchest/captcha/LICENSE b/contrib/backends/nntpchand/src/vendor/github.com/dchest/captcha/LICENSE new file mode 100644 index 0000000..0ad73ae --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/dchest/captcha/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2011-2014 Dmitry Chestnykh + +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/contrib/backends/nntpchand/src/vendor/github.com/dchest/captcha/README.md b/contrib/backends/nntpchand/src/vendor/github.com/dchest/captcha/README.md new file mode 100644 index 0000000..f83f70d --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/dchest/captcha/README.md @@ -0,0 +1,275 @@ +Package captcha +===================== + + import "github.com/dchest/captcha" + +Package captcha implements generation and verification of image and audio +CAPTCHAs. + +A captcha solution is the sequence of digits 0-9 with the defined length. +There are two captcha representations: image and audio. + +An image representation is a PNG-encoded image with the solution printed on +it in such a way that makes it hard for computers to solve it using OCR. + +An audio representation is a WAVE-encoded (8 kHz unsigned 8-bit) sound with the +spoken solution (currently in English, Russian, and Chinese). To make it hard +for computers to solve audio captcha, the voice that pronounces numbers has +random speed and pitch, and there is a randomly generated background noise +mixed into the sound. + +This package doesn't require external files or libraries to generate captcha +representations; it is self-contained. + +To make captchas one-time, the package includes a memory storage that stores +captcha ids, their solutions, and expiration time. Used captchas are removed +from the store immediately after calling Verify or VerifyString, while +unused captchas (user loaded a page with captcha, but didn't submit the +form) are collected automatically after the predefined expiration time. +Developers can also provide custom store (for example, which saves captcha +ids and solutions in database) by implementing Store interface and +registering the object with SetCustomStore. + +Captchas are created by calling New, which returns the captcha id. Their +representations, though, are created on-the-fly by calling WriteImage or +WriteAudio functions. Created representations are not stored anywhere, but +subsequent calls to these functions with the same id will write the same +captcha solution. Reload function will create a new different solution for the +provided captcha, allowing users to "reload" captcha if they can't solve the +displayed one without reloading the whole page. Verify and VerifyString are +used to verify that the given solution is the right one for the given captcha +id. + +Server provides an http.Handler which can serve image and audio +representations of captchas automatically from the URL. It can also be used +to reload captchas. Refer to Server function documentation for details, or +take a look at the example in "capexample" subdirectory. + + +Examples +-------- + +![Image](https://github.com/dchest/captcha/raw/master/capgen/example.png) + +[Audio](https://github.com/dchest/captcha/raw/master/capgen/example.wav) + + +Constants +--------- + +``` go +const ( + // Default number of digits in captcha solution. + DefaultLen = 6 + // The number of captchas created that triggers garbage collection used + // by default store. + CollectNum = 100 + // Expiration time of captchas used by default store. + Expiration = 10 * time.Minute +) +``` + +``` go +const ( + // Standard width and height of a captcha image. + StdWidth = 240 + StdHeight = 80 +) +``` + + +Variables +--------- + +``` go +var ( + ErrNotFound = errors.New("captcha: id not found") +) +``` + + + +Functions +--------- + +### func New + + func New() string + +New creates a new captcha with the standard length, saves it in the internal +storage and returns its id. + +### func NewLen + + func NewLen(length int) (id string) + +NewLen is just like New, but accepts length of a captcha solution as the +argument. + +### func RandomDigits + + func RandomDigits(length int) (b []byte) + +RandomDigits returns a byte slice of the given length containing +pseudorandom numbers in range 0-9. The slice can be used as a captcha +solution. + +### func Reload + + func Reload(id string) bool + +Reload generates and remembers new digits for the given captcha id. This +function returns false if there is no captcha with the given id. + +After calling this function, the image or audio presented to a user must be +refreshed to show the new captcha representation (WriteImage and WriteAudio +will write the new one). + +### func Server + + func Server(imgWidth, imgHeight int) http.Handler + +Server returns a handler that serves HTTP requests with image or +audio representations of captchas. Image dimensions are accepted as +arguments. The server decides which captcha to serve based on the last URL +path component: file name part must contain a captcha id, file extension — +its format (PNG or WAV). + +For example, for file name "LBm5vMjHDtdUfaWYXiQX.png" it serves an image captcha +with id "LBm5vMjHDtdUfaWYXiQX", and for "LBm5vMjHDtdUfaWYXiQX.wav" it serves the +same captcha in audio format. + +To serve a captcha as a downloadable file, the URL must be constructed in +such a way as if the file to serve is in the "download" subdirectory: +"/download/LBm5vMjHDtdUfaWYXiQX.wav". + +To reload captcha (get a different solution for the same captcha id), append +"?reload=x" to URL, where x may be anything (for example, current time or a +random number to make browsers refetch an image instead of loading it from +cache). + +By default, the Server serves audio in English language. To serve audio +captcha in one of the other supported languages, append "lang" value, for +example, "?lang=ru". + +### func SetCustomStore + + func SetCustomStore(s Store) + +SetCustomStore sets custom storage for captchas, replacing the default +memory store. This function must be called before generating any captchas. + +### func Verify + + func Verify(id string, digits []byte) bool + +Verify returns true if the given digits are the ones that were used to +create the given captcha id. + +The function deletes the captcha with the given id from the internal +storage, so that the same captcha can't be verified anymore. + +### func VerifyString + + func VerifyString(id string, digits string) bool + +VerifyString is like Verify, but accepts a string of digits. It removes +spaces and commas from the string, but any other characters, apart from +digits and listed above, will cause the function to return false. + +### func WriteAudio + + func WriteAudio(w io.Writer, id string, lang string) error + +WriteAudio writes WAV-encoded audio representation of the captcha with the +given id and the given language. If there are no sounds for the given +language, English is used. + +### func WriteImage + + func WriteImage(w io.Writer, id string, width, height int) error + +WriteImage writes PNG-encoded image representation of the captcha with the +given id. The image will have the given width and height. + + +Types +----- + +``` go +type Audio struct { + // contains unexported fields +} +``` + + +### func NewAudio + + func NewAudio(id string, digits []byte, lang string) *Audio + +NewAudio returns a new audio captcha with the given digits, where each digit +must be in range 0-9. Digits are pronounced in the given language. If there +are no sounds for the given language, English is used. + +Possible values for lang are "en", "ru", "zh". + +### func (*Audio) EncodedLen + + func (a *Audio) EncodedLen() int + +EncodedLen returns the length of WAV-encoded audio captcha. + +### func (*Audio) WriteTo + + func (a *Audio) WriteTo(w io.Writer) (n int64, err error) + +WriteTo writes captcha audio in WAVE format into the given io.Writer, and +returns the number of bytes written and an error if any. + +``` go +type Image struct { + *image.Paletted + // contains unexported fields +} +``` + + +### func NewImage + + func NewImage(id string, digits []byte, width, height int) *Image + +NewImage returns a new captcha image of the given width and height with the +given digits, where each digit must be in range 0-9. + +### func (*Image) WriteTo + + func (m *Image) WriteTo(w io.Writer) (int64, error) + +WriteTo writes captcha image in PNG format into the given writer. + +``` go +type Store interface { + // Set sets the digits for the captcha id. + Set(id string, digits []byte) + + // Get returns stored digits for the captcha id. Clear indicates + // whether the captcha must be deleted from the store. + Get(id string, clear bool) (digits []byte) +} +``` + +An object implementing Store interface can be registered with SetCustomStore +function to handle storage and retrieval of captcha ids and solutions for +them, replacing the default memory store. + +It is the responsibility of an object to delete expired and used captchas +when necessary (for example, the default memory store collects them in Set +method after the certain amount of captchas has been stored.) + +### func NewMemoryStore + + func NewMemoryStore(collectNum int, expiration time.Duration) Store + +NewMemoryStore returns a new standard memory store for captchas with the +given collection threshold and expiration time in seconds. The returned +store must be registered with SetCustomStore to replace the default one. diff --git a/contrib/backends/nntpchand/src/vendor/github.com/dchest/captcha/audio.go b/contrib/backends/nntpchand/src/vendor/github.com/dchest/captcha/audio.go new file mode 100644 index 0000000..3347f00 --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/dchest/captcha/audio.go @@ -0,0 +1,232 @@ +// Copyright 2011-2014 Dmitry Chestnykh. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package captcha + +import ( + "bytes" + "encoding/binary" + "io" + "math" +) + +const sampleRate = 8000 // Hz + +var endingBeepSound []byte + +func init() { + endingBeepSound = changeSpeed(beepSound, 1.4) +} + +type Audio struct { + body *bytes.Buffer + digitSounds [][]byte + rng siprng +} + +// NewAudio returns a new audio captcha with the given digits, where each digit +// must be in range 0-9. Digits are pronounced in the given language. If there +// are no sounds for the given language, English is used. +// +// Possible values for lang are "en", "ru", "zh". +func NewAudio(id string, digits []byte, lang string) *Audio { + a := new(Audio) + + // Initialize PRNG. + a.rng.Seed(deriveSeed(audioSeedPurpose, id, digits)) + + if sounds, ok := digitSounds[lang]; ok { + a.digitSounds = sounds + } else { + a.digitSounds = digitSounds["en"] + } + numsnd := make([][]byte, len(digits)) + nsdur := 0 + for i, n := range digits { + snd := a.randomizedDigitSound(n) + nsdur += len(snd) + numsnd[i] = snd + } + // Random intervals between digits (including beginning). + intervals := make([]int, len(digits)+1) + intdur := 0 + for i := range intervals { + dur := a.rng.Int(sampleRate, sampleRate*3) // 1 to 3 seconds + intdur += dur + intervals[i] = dur + } + // Generate background sound. + bg := a.makeBackgroundSound(a.longestDigitSndLen()*len(digits) + intdur) + // Create buffer and write audio to it. + sil := makeSilence(sampleRate / 5) + bufcap := 3*len(beepSound) + 2*len(sil) + len(bg) + len(endingBeepSound) + a.body = bytes.NewBuffer(make([]byte, 0, bufcap)) + // Write prelude, three beeps. + a.body.Write(beepSound) + a.body.Write(sil) + a.body.Write(beepSound) + a.body.Write(sil) + a.body.Write(beepSound) + // Write digits. + pos := intervals[0] + for i, v := range numsnd { + mixSound(bg[pos:], v) + pos += len(v) + intervals[i+1] + } + a.body.Write(bg) + // Write ending (one beep). + a.body.Write(endingBeepSound) + return a +} + +// WriteTo writes captcha audio in WAVE format into the given io.Writer, and +// returns the number of bytes written and an error if any. +func (a *Audio) WriteTo(w io.Writer) (n int64, err error) { + // Calculate padded length of PCM chunk data. + bodyLen := uint32(a.body.Len()) + paddedBodyLen := bodyLen + if bodyLen%2 != 0 { + paddedBodyLen++ + } + totalLen := uint32(len(waveHeader)) - 4 + paddedBodyLen + // Header. + header := make([]byte, len(waveHeader)+4) // includes 4 bytes for chunk size + copy(header, waveHeader) + // Put the length of whole RIFF chunk. + binary.LittleEndian.PutUint32(header[4:], totalLen) + // Put the length of WAVE chunk. + binary.LittleEndian.PutUint32(header[len(waveHeader):], bodyLen) + // Write header. + nn, err := w.Write(header) + n = int64(nn) + if err != nil { + return + } + // Write data. + n, err = a.body.WriteTo(w) + n += int64(nn) + if err != nil { + return + } + // Pad byte if chunk length is odd. + // (As header has even length, we can check if n is odd, not chunk). + if bodyLen != paddedBodyLen { + w.Write([]byte{0}) + n++ + } + return +} + +// EncodedLen returns the length of WAV-encoded audio captcha. +func (a *Audio) EncodedLen() int { + return len(waveHeader) + 4 + a.body.Len() +} + +func (a *Audio) makeBackgroundSound(length int) []byte { + b := a.makeWhiteNoise(length, 4) + for i := 0; i < length/(sampleRate/10); i++ { + snd := reversedSound(a.digitSounds[a.rng.Intn(10)]) + snd = changeSpeed(snd, a.rng.Float(0.8, 1.4)) + place := a.rng.Intn(len(b) - len(snd)) + setSoundLevel(snd, a.rng.Float(0.2, 0.5)) + mixSound(b[place:], snd) + } + return b +} + +func (a *Audio) randomizedDigitSound(n byte) []byte { + s := a.randomSpeed(a.digitSounds[n]) + setSoundLevel(s, a.rng.Float(0.75, 1.2)) + return s +} + +func (a *Audio) longestDigitSndLen() int { + n := 0 + for _, v := range a.digitSounds { + if n < len(v) { + n = len(v) + } + } + return n +} + +func (a *Audio) randomSpeed(b []byte) []byte { + pitch := a.rng.Float(0.9, 1.2) + return changeSpeed(b, pitch) +} + +func (a *Audio) makeWhiteNoise(length int, level uint8) []byte { + noise := a.rng.Bytes(length) + adj := 128 - level/2 + for i, v := range noise { + v %= level + v += adj + noise[i] = v + } + return noise +} + +// mixSound mixes src into dst. Dst must have length equal to or greater than +// src length. +func mixSound(dst, src []byte) { + for i, v := range src { + av := int(v) + bv := int(dst[i]) + if av < 128 && bv < 128 { + dst[i] = byte(av * bv / 128) + } else { + dst[i] = byte(2*(av+bv) - av*bv/128 - 256) + } + } +} + +func setSoundLevel(a []byte, level float64) { + for i, v := range a { + av := float64(v) + switch { + case av > 128: + if av = (av-128)*level + 128; av < 128 { + av = 128 + } + case av < 128: + if av = 128 - (128-av)*level; av > 128 { + av = 128 + } + default: + continue + } + a[i] = byte(av) + } +} + +// changeSpeed returns new PCM bytes from the bytes with the speed and pitch +// changed to the given value that must be in range [0, x]. +func changeSpeed(a []byte, speed float64) []byte { + b := make([]byte, int(math.Floor(float64(len(a))*speed))) + var p float64 + for _, v := range a { + for i := int(p); i < int(p+speed); i++ { + b[i] = v + } + p += speed + } + return b +} + +func makeSilence(length int) []byte { + b := make([]byte, length) + for i := range b { + b[i] = 128 + } + return b +} + +func reversedSound(a []byte) []byte { + n := len(a) + b := make([]byte, n) + for i, v := range a { + b[n-1-i] = v + } + return b +} diff --git a/contrib/backends/nntpchand/src/vendor/github.com/dchest/captcha/audio_test.go b/contrib/backends/nntpchand/src/vendor/github.com/dchest/captcha/audio_test.go new file mode 100644 index 0000000..9848f3e --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/dchest/captcha/audio_test.go @@ -0,0 +1,32 @@ +// Copyright 2011 Dmitry Chestnykh. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package captcha + +import ( + "io/ioutil" + "testing" +) + +func BenchmarkNewAudio(b *testing.B) { + b.StopTimer() + d := RandomDigits(DefaultLen) + id := randomId() + b.StartTimer() + for i := 0; i < b.N; i++ { + NewAudio(id, d, "") + } +} + +func BenchmarkAudioWriteTo(b *testing.B) { + b.StopTimer() + d := RandomDigits(DefaultLen) + id := randomId() + b.StartTimer() + for i := 0; i < b.N; i++ { + a := NewAudio(id, d, "") + n, _ := a.WriteTo(ioutil.Discard) + b.SetBytes(n) + } +} diff --git a/contrib/backends/nntpchand/src/vendor/github.com/dchest/captcha/captcha.go b/contrib/backends/nntpchand/src/vendor/github.com/dchest/captcha/captcha.go new file mode 100644 index 0000000..11eb28b --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/dchest/captcha/captcha.go @@ -0,0 +1,165 @@ +// Copyright 2011 Dmitry Chestnykh. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +// Package captcha implements generation and verification of image and audio +// CAPTCHAs. +// +// A captcha solution is the sequence of digits 0-9 with the defined length. +// There are two captcha representations: image and audio. +// +// An image representation is a PNG-encoded image with the solution printed on +// it in such a way that makes it hard for computers to solve it using OCR. +// +// An audio representation is a WAVE-encoded (8 kHz unsigned 8-bit) sound with +// the spoken solution (currently in English, Russian, and Chinese). To make it +// hard for computers to solve audio captcha, the voice that pronounces numbers +// has random speed and pitch, and there is a randomly generated background +// noise mixed into the sound. +// +// This package doesn't require external files or libraries to generate captcha +// representations; it is self-contained. +// +// To make captchas one-time, the package includes a memory storage that stores +// captcha ids, their solutions, and expiration time. Used captchas are removed +// from the store immediately after calling Verify or VerifyString, while +// unused captchas (user loaded a page with captcha, but didn't submit the +// form) are collected automatically after the predefined expiration time. +// Developers can also provide custom store (for example, which saves captcha +// ids and solutions in database) by implementing Store interface and +// registering the object with SetCustomStore. +// +// Captchas are created by calling New, which returns the captcha id. Their +// representations, though, are created on-the-fly by calling WriteImage or +// WriteAudio functions. Created representations are not stored anywhere, but +// subsequent calls to these functions with the same id will write the same +// captcha solution. Reload function will create a new different solution for +// the provided captcha, allowing users to "reload" captcha if they can't solve +// the displayed one without reloading the whole page. Verify and VerifyString +// are used to verify that the given solution is the right one for the given +// captcha id. +// +// Server provides an http.Handler which can serve image and audio +// representations of captchas automatically from the URL. It can also be used +// to reload captchas. Refer to Server function documentation for details, or +// take a look at the example in "capexample" subdirectory. +package captcha + +import ( + "bytes" + "errors" + "io" + "time" +) + +const ( + // Default number of digits in captcha solution. + DefaultLen = 6 + // The number of captchas created that triggers garbage collection used + // by default store. + CollectNum = 100 + // Expiration time of captchas used by default store. + Expiration = 10 * time.Minute +) + +var ( + ErrNotFound = errors.New("captcha: id not found") + // globalStore is a shared storage for captchas, generated by New function. + globalStore = NewMemoryStore(CollectNum, Expiration) +) + +// SetCustomStore sets custom storage for captchas, replacing the default +// memory store. This function must be called before generating any captchas. +func SetCustomStore(s Store) { + globalStore = s +} + +// New creates a new captcha with the standard length, saves it in the internal +// storage and returns its id. +func New() string { + return NewLen(DefaultLen) +} + +// NewLen is just like New, but accepts length of a captcha solution as the +// argument. +func NewLen(length int) (id string) { + id = randomId() + globalStore.Set(id, RandomDigits(length)) + return +} + +// Reload generates and remembers new digits for the given captcha id. This +// function returns false if there is no captcha with the given id. +// +// After calling this function, the image or audio presented to a user must be +// refreshed to show the new captcha representation (WriteImage and WriteAudio +// will write the new one). +func Reload(id string) bool { + old := globalStore.Get(id, false) + if old == nil { + return false + } + globalStore.Set(id, RandomDigits(len(old))) + return true +} + +// WriteImage writes PNG-encoded image representation of the captcha with the +// given id. The image will have the given width and height. +func WriteImage(w io.Writer, id string, width, height int) error { + d := globalStore.Get(id, false) + if d == nil { + return ErrNotFound + } + _, err := NewImage(id, d, width, height).WriteTo(w) + return err +} + +// WriteAudio writes WAV-encoded audio representation of the captcha with the +// given id and the given language. If there are no sounds for the given +// language, English is used. +func WriteAudio(w io.Writer, id string, lang string) error { + d := globalStore.Get(id, false) + if d == nil { + return ErrNotFound + } + _, err := NewAudio(id, d, lang).WriteTo(w) + return err +} + +// Verify returns true if the given digits are the ones that were used to +// create the given captcha id. +// +// The function deletes the captcha with the given id from the internal +// storage, so that the same captcha can't be verified anymore. +func Verify(id string, digits []byte) bool { + if digits == nil || len(digits) == 0 { + return false + } + reald := globalStore.Get(id, true) + if reald == nil { + return false + } + return bytes.Equal(digits, reald) +} + +// VerifyString is like Verify, but accepts a string of digits. It removes +// spaces and commas from the string, but any other characters, apart from +// digits and listed above, will cause the function to return false. +func VerifyString(id string, digits string) bool { + if digits == "" { + return false + } + ns := make([]byte, len(digits)) + for i := range ns { + d := digits[i] + switch { + case '0' <= d && d <= '9': + ns[i] = d - '0' + case d == ' ' || d == ',': + // ignore + default: + return false + } + } + return Verify(id, ns) +} diff --git a/contrib/backends/nntpchand/src/vendor/github.com/dchest/captcha/captcha_test.go b/contrib/backends/nntpchand/src/vendor/github.com/dchest/captcha/captcha_test.go new file mode 100644 index 0000000..de7f7a9 --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/dchest/captcha/captcha_test.go @@ -0,0 +1,52 @@ +// Copyright 2011 Dmitry Chestnykh. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package captcha + +import ( + "bytes" + "testing" +) + +func TestNew(t *testing.T) { + c := New() + if c == "" { + t.Errorf("expected id, got empty string") + } +} + +func TestVerify(t *testing.T) { + id := New() + if Verify(id, []byte{0, 0}) { + t.Errorf("verified wrong captcha") + } + id = New() + d := globalStore.Get(id, false) // cheating + if !Verify(id, d) { + t.Errorf("proper captcha not verified") + } +} + +func TestReload(t *testing.T) { + id := New() + d1 := globalStore.Get(id, false) // cheating + Reload(id) + d2 := globalStore.Get(id, false) // cheating again + if bytes.Equal(d1, d2) { + t.Errorf("reload didn't work: %v = %v", d1, d2) + } +} + +func TestRandomDigits(t *testing.T) { + d1 := RandomDigits(10) + for _, v := range d1 { + if v > 9 { + t.Errorf("digits not in range 0-9: %v", d1) + } + } + d2 := RandomDigits(10) + if bytes.Equal(d1, d2) { + t.Errorf("digits seem to be not random") + } +} diff --git a/contrib/backends/nntpchand/src/vendor/github.com/dchest/captcha/font.go b/contrib/backends/nntpchand/src/vendor/github.com/dchest/captcha/font.go new file mode 100644 index 0000000..fedc54d --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/dchest/captcha/font.go @@ -0,0 +1,214 @@ +// Copyright 2011 Dmitry Chestnykh. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package captcha + +const ( + fontWidth = 11 + fontHeight = 18 + blackChar = 1 +) + +var font = [][]byte{ + { // 0 + 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, + 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, + 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, + 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, + 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, + 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, + 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, + 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, + 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, + 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, + }, + { // 1 + 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, + 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, + 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + }, + { // 2 + 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, + 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, + 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, + 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, + 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + }, + { // 3 + 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, + 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, + 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, + 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, + 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, + 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, + 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, + }, + { // 4 + 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, + 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, + 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, + 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, + 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, + 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, + 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, + 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, + }, + { // 5 + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, + 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, + 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, + 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, + 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, + }, + { // 6 + 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, + 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, + 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, + 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, + 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, + 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, + 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, + 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, + 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, + 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, + 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, + }, + { // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, + 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, + }, + { // 8 + 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, + 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, + 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, + 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, + 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, + 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, + 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, + 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, + 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, + 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, + 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, + 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, + 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, + }, + { // 9 + 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, + 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, + 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, + 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, + 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, + 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, + 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, + 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, + 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, + 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, + 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, + }, +} diff --git a/contrib/backends/nntpchand/src/vendor/github.com/dchest/captcha/image.go b/contrib/backends/nntpchand/src/vendor/github.com/dchest/captcha/image.go new file mode 100644 index 0000000..4cc1f3c --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/dchest/captcha/image.go @@ -0,0 +1,271 @@ +// Copyright 2011-2014 Dmitry Chestnykh. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package captcha + +import ( + "bytes" + "image" + "image/color" + "image/png" + "io" + "math" +) + +const ( + // Standard width and height of a captcha image. + StdWidth = 240 + StdHeight = 80 + // Maximum absolute skew factor of a single digit. + maxSkew = 0.7 + // Number of background circles. + circleCount = 20 +) + +type Image struct { + *image.Paletted + numWidth int + numHeight int + dotSize int + rng siprng +} + +// NewImage returns a new captcha image of the given width and height with the +// given digits, where each digit must be in range 0-9. +func NewImage(id string, digits []byte, width, height int) *Image { + m := new(Image) + + // Initialize PRNG. + m.rng.Seed(deriveSeed(imageSeedPurpose, id, digits)) + + m.Paletted = image.NewPaletted(image.Rect(0, 0, width, height), m.getRandomPalette()) + m.calculateSizes(width, height, len(digits)) + // Randomly position captcha inside the image. + maxx := width - (m.numWidth+m.dotSize)*len(digits) - m.dotSize + maxy := height - m.numHeight - m.dotSize*2 + var border int + if width > height { + border = height / 5 + } else { + border = width / 5 + } + x := m.rng.Int(border, maxx-border) + y := m.rng.Int(border, maxy-border) + // Draw digits. + for _, n := range digits { + m.drawDigit(font[n], x, y) + x += m.numWidth + m.dotSize + } + // Draw strike-through line. + m.strikeThrough() + // Apply wave distortion. + m.distort(m.rng.Float(5, 10), m.rng.Float(100, 200)) + // Fill image with random circles. + m.fillWithCircles(circleCount, m.dotSize) + return m +} + +func (m *Image) getRandomPalette() color.Palette { + p := make([]color.Color, circleCount+1) + // Transparent color. + p[0] = color.RGBA{0xFF, 0xFF, 0xFF, 0x00} + // Primary color. + prim := color.RGBA{ + uint8(m.rng.Intn(129)), + uint8(m.rng.Intn(129)), + uint8(m.rng.Intn(129)), + 0xFF, + } + p[1] = prim + // Circle colors. + for i := 2; i <= circleCount; i++ { + p[i] = m.randomBrightness(prim, 255) + } + return p +} + +// encodedPNG encodes an image to PNG and returns +// the result as a byte slice. +func (m *Image) encodedPNG() []byte { + var buf bytes.Buffer + if err := png.Encode(&buf, m.Paletted); err != nil { + panic(err.Error()) + } + return buf.Bytes() +} + +// WriteTo writes captcha image in PNG format into the given writer. +func (m *Image) WriteTo(w io.Writer) (int64, error) { + n, err := w.Write(m.encodedPNG()) + return int64(n), err +} + +func (m *Image) calculateSizes(width, height, ncount int) { + // Goal: fit all digits inside the image. + var border int + if width > height { + border = height / 4 + } else { + border = width / 4 + } + // Convert everything to floats for calculations. + w := float64(width - border*2) + h := float64(height - border*2) + // fw takes into account 1-dot spacing between digits. + fw := float64(fontWidth + 1) + fh := float64(fontHeight) + nc := float64(ncount) + // Calculate the width of a single digit taking into account only the + // width of the image. + nw := w / nc + // Calculate the height of a digit from this width. + nh := nw * fh / fw + // Digit too high? + if nh > h { + // Fit digits based on height. + nh = h + nw = fw / fh * nh + } + // Calculate dot size. + m.dotSize = int(nh / fh) + if m.dotSize < 1 { + m.dotSize = 1 + } + // Save everything, making the actual width smaller by 1 dot to account + // for spacing between digits. + m.numWidth = int(nw) - m.dotSize + m.numHeight = int(nh) +} + +func (m *Image) drawHorizLine(fromX, toX, y int, colorIdx uint8) { + for x := fromX; x <= toX; x++ { + m.SetColorIndex(x, y, colorIdx) + } +} + +func (m *Image) drawCircle(x, y, radius int, colorIdx uint8) { + f := 1 - radius + dfx := 1 + dfy := -2 * radius + xo := 0 + yo := radius + + m.SetColorIndex(x, y+radius, colorIdx) + m.SetColorIndex(x, y-radius, colorIdx) + m.drawHorizLine(x-radius, x+radius, y, colorIdx) + + for xo < yo { + if f >= 0 { + yo-- + dfy += 2 + f += dfy + } + xo++ + dfx += 2 + f += dfx + m.drawHorizLine(x-xo, x+xo, y+yo, colorIdx) + m.drawHorizLine(x-xo, x+xo, y-yo, colorIdx) + m.drawHorizLine(x-yo, x+yo, y+xo, colorIdx) + m.drawHorizLine(x-yo, x+yo, y-xo, colorIdx) + } +} + +func (m *Image) fillWithCircles(n, maxradius int) { + maxx := m.Bounds().Max.X + maxy := m.Bounds().Max.Y + for i := 0; i < n; i++ { + colorIdx := uint8(m.rng.Int(1, circleCount-1)) + r := m.rng.Int(1, maxradius) + m.drawCircle(m.rng.Int(r, maxx-r), m.rng.Int(r, maxy-r), r, colorIdx) + } +} + +func (m *Image) strikeThrough() { + maxx := m.Bounds().Max.X + maxy := m.Bounds().Max.Y + y := m.rng.Int(maxy/3, maxy-maxy/3) + amplitude := m.rng.Float(5, 20) + period := m.rng.Float(80, 180) + dx := 2.0 * math.Pi / period + for x := 0; x < maxx; x++ { + xo := amplitude * math.Cos(float64(y)*dx) + yo := amplitude * math.Sin(float64(x)*dx) + for yn := 0; yn < m.dotSize; yn++ { + r := m.rng.Int(0, m.dotSize) + m.drawCircle(x+int(xo), y+int(yo)+(yn*m.dotSize), r/2, 1) + } + } +} + +func (m *Image) drawDigit(digit []byte, x, y int) { + skf := m.rng.Float(-maxSkew, maxSkew) + xs := float64(x) + r := m.dotSize / 2 + y += m.rng.Int(-r, r) + for yo := 0; yo < fontHeight; yo++ { + for xo := 0; xo < fontWidth; xo++ { + if digit[yo*fontWidth+xo] != blackChar { + continue + } + m.drawCircle(x+xo*m.dotSize, y+yo*m.dotSize, r, 1) + } + xs += skf + x = int(xs) + } +} + +func (m *Image) distort(amplude float64, period float64) { + w := m.Bounds().Max.X + h := m.Bounds().Max.Y + + oldm := m.Paletted + newm := image.NewPaletted(image.Rect(0, 0, w, h), oldm.Palette) + + dx := 2.0 * math.Pi / period + for x := 0; x < w; x++ { + for y := 0; y < h; y++ { + xo := amplude * math.Sin(float64(y)*dx) + yo := amplude * math.Cos(float64(x)*dx) + newm.SetColorIndex(x, y, oldm.ColorIndexAt(x+int(xo), y+int(yo))) + } + } + m.Paletted = newm +} + +func (m *Image) randomBrightness(c color.RGBA, max uint8) color.RGBA { + minc := min3(c.R, c.G, c.B) + maxc := max3(c.R, c.G, c.B) + if maxc > max { + return c + } + n := m.rng.Intn(int(max-maxc)) - int(minc) + return color.RGBA{ + uint8(int(c.R) + n), + uint8(int(c.G) + n), + uint8(int(c.B) + n), + uint8(c.A), + } +} + +func min3(x, y, z uint8) (m uint8) { + m = x + if y < m { + m = y + } + if z < m { + m = z + } + return +} + +func max3(x, y, z uint8) (m uint8) { + m = x + if y > m { + m = y + } + if z > m { + m = z + } + return +} diff --git a/contrib/backends/nntpchand/src/vendor/github.com/dchest/captcha/image_test.go b/contrib/backends/nntpchand/src/vendor/github.com/dchest/captcha/image_test.go new file mode 100644 index 0000000..5e10ce3 --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/dchest/captcha/image_test.go @@ -0,0 +1,40 @@ +// Copyright 2011 Dmitry Chestnykh. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package captcha + +import "testing" + +type byteCounter struct { + n int64 +} + +func (bc *byteCounter) Write(b []byte) (int, error) { + bc.n += int64(len(b)) + return len(b), nil +} + +func BenchmarkNewImage(b *testing.B) { + b.StopTimer() + d := RandomDigits(DefaultLen) + id := randomId() + b.StartTimer() + for i := 0; i < b.N; i++ { + NewImage(id, d, StdWidth, StdHeight) + } +} + +func BenchmarkImageWriteTo(b *testing.B) { + b.StopTimer() + d := RandomDigits(DefaultLen) + id := randomId() + b.StartTimer() + counter := &byteCounter{} + for i := 0; i < b.N; i++ { + img := NewImage(id, d, StdWidth, StdHeight) + img.WriteTo(counter) + b.SetBytes(counter.n) + counter.n = 0 + } +} diff --git a/contrib/backends/nntpchand/src/vendor/github.com/dchest/captcha/random.go b/contrib/backends/nntpchand/src/vendor/github.com/dchest/captcha/random.go new file mode 100644 index 0000000..96703c2 --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/dchest/captcha/random.go @@ -0,0 +1,108 @@ +// Copyright 2011-2014 Dmitry Chestnykh. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package captcha + +import ( + "crypto/hmac" + "crypto/rand" + "crypto/sha256" + "io" +) + +// idLen is a length of captcha id string. +// (20 bytes of 62-letter alphabet give ~119 bits.) +const idLen = 20 + +// idChars are characters allowed in captcha id. +var idChars = []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") + +// rngKey is a secret key used to deterministically derive seeds for +// PRNGs used in image and audio. Generated once during initialization. +var rngKey [32]byte + +func init() { + if _, err := io.ReadFull(rand.Reader, rngKey[:]); err != nil { + panic("captcha: error reading random source: " + err.Error()) + } +} + +// Purposes for seed derivation. The goal is to make deterministic PRNG produce +// different outputs for images and audio by using different derived seeds. +const ( + imageSeedPurpose = 0x01 + audioSeedPurpose = 0x02 +) + +// deriveSeed returns a 16-byte PRNG seed from rngKey, purpose, id and digits. +// Same purpose, id and digits will result in the same derived seed for this +// instance of running application. +// +// out = HMAC(rngKey, purpose || id || 0x00 || digits) (cut to 16 bytes) +// +func deriveSeed(purpose byte, id string, digits []byte) (out [16]byte) { + var buf [sha256.Size]byte + h := hmac.New(sha256.New, rngKey[:]) + h.Write([]byte{purpose}) + io.WriteString(h, id) + h.Write([]byte{0}) + h.Write(digits) + sum := h.Sum(buf[:0]) + copy(out[:], sum) + return +} + +// RandomDigits returns a byte slice of the given length containing +// pseudorandom numbers in range 0-9. The slice can be used as a captcha +// solution. +func RandomDigits(length int) []byte { + return randomBytesMod(length, 10) +} + +// randomBytes returns a byte slice of the given length read from CSPRNG. +func randomBytes(length int) (b []byte) { + b = make([]byte, length) + if _, err := io.ReadFull(rand.Reader, b); err != nil { + panic("captcha: error reading random source: " + err.Error()) + } + return +} + +// randomBytesMod returns a byte slice of the given length, where each byte is +// a random number modulo mod. +func randomBytesMod(length int, mod byte) (b []byte) { + if length == 0 { + return nil + } + if mod == 0 { + panic("captcha: bad mod argument for randomBytesMod") + } + maxrb := 255 - byte(256%int(mod)) + b = make([]byte, length) + i := 0 + for { + r := randomBytes(length + (length / 4)) + for _, c := range r { + if c > maxrb { + // Skip this number to avoid modulo bias. + continue + } + b[i] = c % mod + i++ + if i == length { + return + } + } + } + +} + +// randomId returns a new random id string. +func randomId() string { + b := randomBytesMod(idLen, byte(len(idChars))) + for i, c := range b { + b[i] = idChars[c] + } + return string(b) +} diff --git a/contrib/backends/nntpchand/src/vendor/github.com/dchest/captcha/server.go b/contrib/backends/nntpchand/src/vendor/github.com/dchest/captcha/server.go new file mode 100644 index 0000000..cae2a14 --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/dchest/captcha/server.go @@ -0,0 +1,87 @@ +// Copyright 2011 Dmitry Chestnykh. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package captcha + +import ( + "bytes" + "net/http" + "path" + "strings" + "time" +) + +type captchaHandler struct { + imgWidth int + imgHeight int +} + +// Server returns a handler that serves HTTP requests with image or +// audio representations of captchas. Image dimensions are accepted as +// arguments. The server decides which captcha to serve based on the last URL +// path component: file name part must contain a captcha id, file extension — +// its format (PNG or WAV). +// +// For example, for file name "LBm5vMjHDtdUfaWYXiQX.png" it serves an image captcha +// with id "LBm5vMjHDtdUfaWYXiQX", and for "LBm5vMjHDtdUfaWYXiQX.wav" it serves the +// same captcha in audio format. +// +// To serve a captcha as a downloadable file, the URL must be constructed in +// such a way as if the file to serve is in the "download" subdirectory: +// "/download/LBm5vMjHDtdUfaWYXiQX.wav". +// +// To reload captcha (get a different solution for the same captcha id), append +// "?reload=x" to URL, where x may be anything (for example, current time or a +// random number to make browsers refetch an image instead of loading it from +// cache). +// +// By default, the Server serves audio in English language. To serve audio +// captcha in one of the other supported languages, append "lang" value, for +// example, "?lang=ru". +func Server(imgWidth, imgHeight int) http.Handler { + return &captchaHandler{imgWidth, imgHeight} +} + +func (h *captchaHandler) serve(w http.ResponseWriter, r *http.Request, id, ext, lang string, download bool) error { + w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate") + w.Header().Set("Pragma", "no-cache") + w.Header().Set("Expires", "0") + + var content bytes.Buffer + switch ext { + case ".png": + w.Header().Set("Content-Type", "image/png") + WriteImage(&content, id, h.imgWidth, h.imgHeight) + case ".wav": + w.Header().Set("Content-Type", "audio/x-wav") + WriteAudio(&content, id, lang) + default: + return ErrNotFound + } + + if download { + w.Header().Set("Content-Type", "application/octet-stream") + } + http.ServeContent(w, r, id+ext, time.Time{}, bytes.NewReader(content.Bytes())) + return nil +} + +func (h *captchaHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + dir, file := path.Split(r.URL.Path) + ext := path.Ext(file) + id := file[:len(file)-len(ext)] + if ext == "" || id == "" { + http.NotFound(w, r) + return + } + if r.FormValue("reload") != "" { + Reload(id) + } + lang := strings.ToLower(r.FormValue("lang")) + download := path.Base(dir) == "download" + if h.serve(w, r, id, ext, lang, download) == ErrNotFound { + http.NotFound(w, r) + } + // Ignore other errors. +} diff --git a/contrib/backends/nntpchand/src/vendor/github.com/dchest/captcha/siprng.go b/contrib/backends/nntpchand/src/vendor/github.com/dchest/captcha/siprng.go new file mode 100644 index 0000000..c604e2c --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/dchest/captcha/siprng.go @@ -0,0 +1,278 @@ +// Copyright 2014 Dmitry Chestnykh. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package captcha + +import "encoding/binary" + +// siprng is PRNG based on SipHash-2-4. +// (Note: it's not safe to use a single siprng from multiple goroutines.) +type siprng struct { + k0, k1, ctr uint64 +} + +// siphash implements SipHash-2-4, accepting a uint64 as a message. +func siphash(k0, k1, m uint64) uint64 { + // Initialization. + v0 := k0 ^ 0x736f6d6570736575 + v1 := k1 ^ 0x646f72616e646f6d + v2 := k0 ^ 0x6c7967656e657261 + v3 := k1 ^ 0x7465646279746573 + t := uint64(8) << 56 + + // Compression. + v3 ^= m + + // Round 1. + v0 += v1 + v1 = v1<<13 | v1>>(64-13) + v1 ^= v0 + v0 = v0<<32 | v0>>(64-32) + + v2 += v3 + v3 = v3<<16 | v3>>(64-16) + v3 ^= v2 + + v0 += v3 + v3 = v3<<21 | v3>>(64-21) + v3 ^= v0 + + v2 += v1 + v1 = v1<<17 | v1>>(64-17) + v1 ^= v2 + v2 = v2<<32 | v2>>(64-32) + + // Round 2. + v0 += v1 + v1 = v1<<13 | v1>>(64-13) + v1 ^= v0 + v0 = v0<<32 | v0>>(64-32) + + v2 += v3 + v3 = v3<<16 | v3>>(64-16) + v3 ^= v2 + + v0 += v3 + v3 = v3<<21 | v3>>(64-21) + v3 ^= v0 + + v2 += v1 + v1 = v1<<17 | v1>>(64-17) + v1 ^= v2 + v2 = v2<<32 | v2>>(64-32) + + v0 ^= m + + // Compress last block. + v3 ^= t + + // Round 1. + v0 += v1 + v1 = v1<<13 | v1>>(64-13) + v1 ^= v0 + v0 = v0<<32 | v0>>(64-32) + + v2 += v3 + v3 = v3<<16 | v3>>(64-16) + v3 ^= v2 + + v0 += v3 + v3 = v3<<21 | v3>>(64-21) + v3 ^= v0 + + v2 += v1 + v1 = v1<<17 | v1>>(64-17) + v1 ^= v2 + v2 = v2<<32 | v2>>(64-32) + + // Round 2. + v0 += v1 + v1 = v1<<13 | v1>>(64-13) + v1 ^= v0 + v0 = v0<<32 | v0>>(64-32) + + v2 += v3 + v3 = v3<<16 | v3>>(64-16) + v3 ^= v2 + + v0 += v3 + v3 = v3<<21 | v3>>(64-21) + v3 ^= v0 + + v2 += v1 + v1 = v1<<17 | v1>>(64-17) + v1 ^= v2 + v2 = v2<<32 | v2>>(64-32) + + v0 ^= t + + // Finalization. + v2 ^= 0xff + + // Round 1. + v0 += v1 + v1 = v1<<13 | v1>>(64-13) + v1 ^= v0 + v0 = v0<<32 | v0>>(64-32) + + v2 += v3 + v3 = v3<<16 | v3>>(64-16) + v3 ^= v2 + + v0 += v3 + v3 = v3<<21 | v3>>(64-21) + v3 ^= v0 + + v2 += v1 + v1 = v1<<17 | v1>>(64-17) + v1 ^= v2 + v2 = v2<<32 | v2>>(64-32) + + // Round 2. + v0 += v1 + v1 = v1<<13 | v1>>(64-13) + v1 ^= v0 + v0 = v0<<32 | v0>>(64-32) + + v2 += v3 + v3 = v3<<16 | v3>>(64-16) + v3 ^= v2 + + v0 += v3 + v3 = v3<<21 | v3>>(64-21) + v3 ^= v0 + + v2 += v1 + v1 = v1<<17 | v1>>(64-17) + v1 ^= v2 + v2 = v2<<32 | v2>>(64-32) + + // Round 3. + v0 += v1 + v1 = v1<<13 | v1>>(64-13) + v1 ^= v0 + v0 = v0<<32 | v0>>(64-32) + + v2 += v3 + v3 = v3<<16 | v3>>(64-16) + v3 ^= v2 + + v0 += v3 + v3 = v3<<21 | v3>>(64-21) + v3 ^= v0 + + v2 += v1 + v1 = v1<<17 | v1>>(64-17) + v1 ^= v2 + v2 = v2<<32 | v2>>(64-32) + + // Round 4. + v0 += v1 + v1 = v1<<13 | v1>>(64-13) + v1 ^= v0 + v0 = v0<<32 | v0>>(64-32) + + v2 += v3 + v3 = v3<<16 | v3>>(64-16) + v3 ^= v2 + + v0 += v3 + v3 = v3<<21 | v3>>(64-21) + v3 ^= v0 + + v2 += v1 + v1 = v1<<17 | v1>>(64-17) + v1 ^= v2 + v2 = v2<<32 | v2>>(64-32) + + return v0 ^ v1 ^ v2 ^ v3 +} + +// SetSeed sets a new secret seed for PRNG. +func (p *siprng) Seed(k [16]byte) { + p.k0 = binary.LittleEndian.Uint64(k[0:8]) + p.k1 = binary.LittleEndian.Uint64(k[8:16]) + p.ctr = 1 +} + +// Uint64 returns a new pseudorandom uint64. +func (p *siprng) Uint64() uint64 { + v := siphash(p.k0, p.k1, p.ctr) + p.ctr++ + return v +} + +func (p *siprng) Bytes(n int) []byte { + // Since we don't have a buffer for generated bytes in siprng state, + // we just generate enough 8-byte blocks and then cut the result to the + // required length. Doing it this way, we lose generated bytes, and we + // don't get the strictly sequential deterministic output from PRNG: + // calling Uint64() and then Bytes(3) produces different output than + // when calling them in the reverse order, but for our applications + // this is OK. + numBlocks := (n + 8 - 1) / 8 + b := make([]byte, numBlocks*8) + for i := 0; i < len(b); i += 8 { + binary.LittleEndian.PutUint64(b[i:], p.Uint64()) + } + return b[:n] +} + +func (p *siprng) Int63() int64 { + return int64(p.Uint64() & 0x7fffffffffffffff) +} + +func (p *siprng) Uint32() uint32 { + return uint32(p.Uint64()) +} + +func (p *siprng) Int31() int32 { + return int32(p.Uint32() & 0x7fffffff) +} + +func (p *siprng) Intn(n int) int { + if n <= 0 { + panic("invalid argument to Intn") + } + if n <= 1<<31-1 { + return int(p.Int31n(int32(n))) + } + return int(p.Int63n(int64(n))) +} + +func (p *siprng) Int63n(n int64) int64 { + if n <= 0 { + panic("invalid argument to Int63n") + } + max := int64((1 << 63) - 1 - (1<<63)%uint64(n)) + v := p.Int63() + for v > max { + v = p.Int63() + } + return v % n +} + +func (p *siprng) Int31n(n int32) int32 { + if n <= 0 { + panic("invalid argument to Int31n") + } + max := int32((1 << 31) - 1 - (1<<31)%uint32(n)) + v := p.Int31() + for v > max { + v = p.Int31() + } + return v % n +} + +func (p *siprng) Float64() float64 { return float64(p.Int63()) / (1 << 63) } + +// Int returns a pseudorandom int in range [from, to]. +func (p *siprng) Int(from, to int) int { + return p.Intn(to+1-from) + from +} + +// Float returns a pseudorandom float64 in range [from, to]. +func (p *siprng) Float(from, to float64) float64 { + return (to-from)*p.Float64() + from +} diff --git a/contrib/backends/nntpchand/src/vendor/github.com/dchest/captcha/siprng_test.go b/contrib/backends/nntpchand/src/vendor/github.com/dchest/captcha/siprng_test.go new file mode 100644 index 0000000..0a0327f --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/dchest/captcha/siprng_test.go @@ -0,0 +1,54 @@ +package captcha + +import ( + "bytes" + "testing" +) + +func TestSiphash(t *testing.T) { + good := uint64(0xe849e8bb6ffe2567) + cur := siphash(0, 0, 0) + if cur != good { + t.Fatalf("siphash: expected %x, got %x", good, cur) + } +} + +func TestSiprng(t *testing.T) { + m := make(map[uint64]interface{}) + var yes interface{} + r := siprng{} + r.Seed([16]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}) + for i := 0; i < 100000; i++ { + v := r.Uint64() + if _, ok := m[v]; ok { + t.Errorf("siphash: collision on %d: %x", i, v) + } + m[v] = yes + } +} + +func TestSiprngBytes(t *testing.T) { + r := siprng{} + r.Seed([16]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}) + x := r.Bytes(32) + if len(x) != 32 { + t.Fatalf("siphash: wrong length: expected 32, got %d", len(x)) + } + y := r.Bytes(32) + if bytes.Equal(x, y) { + t.Fatalf("siphash: stream repeats: %x = %x", x, y) + } + r.Seed([16]byte{}) + z := r.Bytes(32) + if bytes.Equal(z, x) { + t.Fatalf("siphash: outputs under different keys repeat: %x = %x", z, x) + } +} + +func BenchmarkSiprng(b *testing.B) { + b.SetBytes(8) + p := &siprng{} + for i := 0; i < b.N; i++ { + p.Uint64() + } +} diff --git a/contrib/backends/nntpchand/src/vendor/github.com/dchest/captcha/sounds.go b/contrib/backends/nntpchand/src/vendor/github.com/dchest/captcha/sounds.go new file mode 100644 index 0000000..d864d3b --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/dchest/captcha/sounds.go @@ -0,0 +1,7390 @@ +package captcha + +// This file has been generated from .wav files using generate.go. + +var waveHeader = []byte{ + 0x52, 0x49, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x57, 0x41, 0x56, 0x45, + 0x66, 0x6d, 0x74, 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x40, 0x1f, 0x00, 0x00, 0x40, 0x1f, 0x00, 0x00, 0x01, 0x00, 0x08, 0x00, + 0x64, 0x61, 0x74, 0x61, +} + +// Byte slices contain raw 8 kHz unsigned 8-bit PCM data (without wav header). + +var digitSounds = map[string][][]byte{ + "en": [][]byte{ + { // 0 + 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, + 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, + 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x7f, + 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x7e, 0x7d, + 0x7e, 0x7c, 0x7e, 0x7e, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x82, 0x81, + 0x83, 0x82, 0x84, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8a, + 0x8c, 0x8a, 0x8b, 0x8b, 0x8a, 0x8a, 0x88, 0x88, 0x86, 0x84, 0x82, + 0x80, 0x7e, 0x7c, 0x7c, 0x7b, 0x7c, 0x79, 0x77, 0x78, 0x76, 0x75, + 0x73, 0x75, 0x75, 0x75, 0x73, 0x72, 0x71, 0x73, 0x76, 0x70, 0x76, + 0x71, 0x77, 0x75, 0x74, 0x78, 0x73, 0x79, 0x76, 0x76, 0x75, 0x75, + 0x75, 0x79, 0x7f, 0x80, 0x81, 0x83, 0x88, 0x8d, 0x90, 0x91, 0x91, + 0x94, 0x98, 0x97, 0x97, 0x95, 0x94, 0x93, 0x92, 0x8d, 0x8a, 0x86, + 0x84, 0x81, 0x81, 0x7f, 0x7f, 0x80, 0x7f, 0x81, 0x81, 0x85, 0x81, + 0x85, 0x85, 0x86, 0x88, 0x84, 0x83, 0x7d, 0x79, 0x77, 0x77, 0x77, + 0x75, 0x72, 0x75, 0x75, 0x75, 0x72, 0x73, 0x72, 0x76, 0x76, 0x74, + 0x74, 0x75, 0x77, 0x78, 0x79, 0x76, 0x79, 0x78, 0x7c, 0x7c, 0x7c, + 0x7d, 0x7e, 0x7e, 0x7f, 0x7b, 0x7e, 0x7c, 0x7e, 0x7f, 0x80, 0x80, + 0x7f, 0x85, 0x84, 0x89, 0x85, 0x89, 0x8c, 0x8e, 0x8e, 0x8d, 0x90, + 0x90, 0x91, 0x8c, 0x8d, 0x89, 0x8c, 0x8a, 0x88, 0x89, 0x84, 0x87, + 0x85, 0x86, 0x83, 0x84, 0x82, 0x7f, 0x85, 0x81, 0x81, 0x7e, 0x80, + 0x7d, 0x7e, 0x7e, 0x79, 0x7c, 0x7a, 0x7a, 0x79, 0x79, 0x77, 0x78, + 0x79, 0x77, 0x76, 0x79, 0x78, 0x79, 0x77, 0x79, 0x79, 0x79, 0x78, + 0x78, 0x7a, 0x78, 0x7b, 0x79, 0x7a, 0x79, 0x7b, 0x7b, 0x79, 0x7c, + 0x79, 0x7d, 0x7c, 0x7d, 0x7d, 0x7c, 0x7e, 0x7d, 0x7f, 0x7c, 0x7f, + 0x7c, 0x7f, 0x7f, 0x82, 0x81, 0x82, 0x84, 0x82, 0x89, 0x82, 0x8a, + 0x83, 0x8b, 0x88, 0x86, 0x8b, 0x85, 0x8d, 0x86, 0x89, 0x84, 0x89, + 0x88, 0x84, 0x84, 0x83, 0x85, 0x83, 0x82, 0x80, 0x84, 0x81, 0x83, + 0x7f, 0x80, 0x82, 0x7e, 0x81, 0x7c, 0x7f, 0x7d, 0x7c, 0x7c, 0x7b, + 0x7d, 0x7a, 0x7d, 0x79, 0x7c, 0x7b, 0x7a, 0x7d, 0x79, 0x7d, 0x7d, + 0x7b, 0x7d, 0x79, 0x7e, 0x7d, 0x79, 0x7d, 0x7a, 0x7d, 0x7f, 0x7b, + 0x7d, 0x7c, 0x7d, 0x7d, 0x7a, 0x7e, 0x7c, 0x7e, 0x7e, 0x7c, 0x7e, + 0x7f, 0x81, 0x7f, 0x7d, 0x81, 0x80, 0x82, 0x80, 0x81, 0x84, 0x85, + 0x87, 0x84, 0x85, 0x86, 0x8a, 0x85, 0x88, 0x85, 0x8b, 0x87, 0x88, + 0x87, 0x84, 0x89, 0x84, 0x86, 0x81, 0x84, 0x84, 0x82, 0x83, 0x81, + 0x81, 0x83, 0x81, 0x80, 0x7e, 0x82, 0x7c, 0x80, 0x7e, 0x7b, 0x82, + 0x78, 0x7f, 0x7c, 0x79, 0x7e, 0x77, 0x7c, 0x7e, 0x7a, 0x7b, 0x7a, + 0x7c, 0x7d, 0x77, 0x7b, 0x7a, 0x7e, 0x7e, 0x7a, 0x7e, 0x7a, 0x7d, + 0x7a, 0x7b, 0x7c, 0x7b, 0x7e, 0x7b, 0x7a, 0x7f, 0x7c, 0x7c, 0x7d, + 0x7b, 0x7f, 0x7e, 0x7f, 0x7c, 0x80, 0x80, 0x80, 0x80, 0x81, 0x82, + 0x82, 0x85, 0x82, 0x88, 0x83, 0x88, 0x84, 0x88, 0x89, 0x85, 0x88, + 0x85, 0x8a, 0x85, 0x86, 0x85, 0x86, 0x86, 0x83, 0x81, 0x84, 0x85, + 0x81, 0x7f, 0x80, 0x81, 0x81, 0x7e, 0x7c, 0x7e, 0x85, 0x7c, 0x7b, + 0x7d, 0x81, 0x7f, 0x77, 0x7d, 0x77, 0x85, 0x79, 0x78, 0x7e, 0x78, + 0x82, 0x72, 0x7e, 0x7c, 0x7b, 0x80, 0x76, 0x7f, 0x7e, 0x7a, 0x76, + 0x7d, 0x7c, 0x76, 0x7b, 0x75, 0x7b, 0x7a, 0x77, 0x77, 0x77, 0x7e, + 0x7c, 0x7a, 0x7a, 0x83, 0x87, 0x7d, 0x86, 0x84, 0x8c, 0x8a, 0x87, + 0x89, 0x8b, 0x90, 0x87, 0x88, 0x86, 0x8f, 0x89, 0x83, 0x89, 0x86, + 0x89, 0x89, 0x7c, 0x87, 0x88, 0x80, 0x81, 0x7f, 0x87, 0x82, 0x81, + 0x7d, 0x85, 0x84, 0x7a, 0x7e, 0x7f, 0x7b, 0x83, 0x78, 0x79, 0x82, + 0x78, 0x7c, 0x76, 0x7b, 0x78, 0x7b, 0x78, 0x72, 0x7e, 0x76, 0x6f, + 0x78, 0x74, 0x6a, 0x77, 0x6b, 0x6a, 0x6c, 0x6d, 0x64, 0x6a, 0x71, + 0x6b, 0x77, 0x79, 0x7d, 0x84, 0x8d, 0x88, 0x90, 0x9a, 0x96, 0x98, + 0x9c, 0x9d, 0x9a, 0x9a, 0x95, 0x94, 0x93, 0x8b, 0x87, 0x87, 0x83, + 0x82, 0x84, 0x7f, 0x82, 0x84, 0x84, 0x82, 0x89, 0x8b, 0x86, 0x8e, + 0x8b, 0x87, 0x86, 0x85, 0x80, 0x7b, 0x7e, 0x78, 0x76, 0x71, 0x6e, + 0x6d, 0x64, 0x69, 0x66, 0x66, 0x61, 0x62, 0x61, 0x59, 0x62, 0x54, + 0x5e, 0x62, 0x5d, 0x6f, 0x71, 0x7e, 0x82, 0x8d, 0x94, 0x9d, 0xa5, + 0xa1, 0xaf, 0xad, 0xad, 0xa8, 0xa8, 0xa3, 0x9b, 0x96, 0x89, 0x88, + 0x81, 0x78, 0x75, 0x75, 0x75, 0x74, 0x77, 0x7c, 0x83, 0x88, 0x90, + 0x95, 0x9a, 0xa0, 0x9d, 0x9f, 0x9c, 0x93, 0x8b, 0x83, 0x7c, 0x74, + 0x6c, 0x65, 0x60, 0x5d, 0x59, 0x57, 0x56, 0x56, 0x55, 0x55, 0x50, + 0x51, 0x4f, 0x51, 0x57, 0x5e, 0x7a, 0x81, 0x82, 0x93, 0xa3, 0xaa, + 0xa6, 0xae, 0xb7, 0xb5, 0xae, 0xa4, 0xa5, 0x9f, 0x8e, 0x84, 0x80, + 0x7d, 0x72, 0x6c, 0x70, 0x73, 0x72, 0x75, 0x7e, 0x88, 0x8f, 0x96, + 0x9e, 0xa8, 0xad, 0xa7, 0xa5, 0xa1, 0x97, 0x8c, 0x82, 0x7b, 0x72, + 0x6b, 0x65, 0x61, 0x5d, 0x58, 0x59, 0x59, 0x55, 0x54, 0x54, 0x4e, + 0x4b, 0x4a, 0x4b, 0x52, 0x5d, 0x77, 0x87, 0x84, 0x91, 0xaa, 0xb0, + 0xa6, 0xae, 0xb8, 0xb2, 0xaa, 0xa2, 0x9b, 0x96, 0x8b, 0x7d, 0x77, + 0x79, 0x70, 0x69, 0x70, 0x76, 0x76, 0x7b, 0x83, 0x8f, 0x97, 0x9d, + 0xa5, 0xa9, 0xaf, 0xa9, 0xa0, 0x9e, 0x94, 0x85, 0x7b, 0x76, 0x6e, + 0x66, 0x64, 0x61, 0x60, 0x5f, 0x5e, 0x5e, 0x5f, 0x5c, 0x58, 0x57, + 0x50, 0x4a, 0x47, 0x4e, 0x53, 0x64, 0x86, 0x7f, 0x81, 0xa4, 0xb1, + 0xa8, 0xa8, 0xb8, 0xb7, 0xaa, 0xa4, 0x9d, 0x97, 0x8c, 0x7e, 0x74, + 0x73, 0x73, 0x69, 0x69, 0x74, 0x7a, 0x7d, 0x84, 0x90, 0x9a, 0xa0, + 0xa6, 0xa8, 0xab, 0xab, 0x9e, 0x96, 0x90, 0x85, 0x78, 0x70, 0x6f, + 0x69, 0x65, 0x65, 0x67, 0x67, 0x66, 0x67, 0x66, 0x66, 0x61, 0x5b, + 0x56, 0x4d, 0x48, 0x47, 0x4e, 0x55, 0x6a, 0x86, 0x82, 0x8a, 0xa6, + 0xb4, 0xad, 0xa9, 0xb5, 0xb5, 0xa9, 0x9d, 0x93, 0x8b, 0x7f, 0x74, + 0x6a, 0x66, 0x6b, 0x6d, 0x6d, 0x74, 0x82, 0x8d, 0x91, 0x99, 0xa4, + 0xab, 0xab, 0xaa, 0xa7, 0xa0, 0x97, 0x89, 0x7c, 0x75, 0x6e, 0x65, + 0x62, 0x68, 0x69, 0x68, 0x6d, 0x72, 0x73, 0x71, 0x73, 0x71, 0x6e, + 0x68, 0x5f, 0x55, 0x4b, 0x47, 0x45, 0x4a, 0x52, 0x64, 0x80, 0x87, + 0x8a, 0xa0, 0xb3, 0xb4, 0xaa, 0xae, 0xb3, 0xa9, 0x9a, 0x8c, 0x83, + 0x79, 0x71, 0x6a, 0x63, 0x68, 0x72, 0x76, 0x7a, 0x86, 0x95, 0x9b, + 0x9d, 0xa2, 0xa6, 0xa5, 0xa0, 0x99, 0x8e, 0x86, 0x7e, 0x73, 0x6c, + 0x6a, 0x6d, 0x6d, 0x71, 0x78, 0x7d, 0x84, 0x84, 0x81, 0x7f, 0x7a, + 0x73, 0x68, 0x5e, 0x55, 0x4b, 0x46, 0x42, 0x40, 0x3f, 0x44, 0x4d, + 0x62, 0x84, 0x98, 0xa0, 0xa9, 0xbc, 0xc3, 0xb7, 0xab, 0xa3, 0x9b, + 0x8e, 0x7b, 0x6b, 0x5f, 0x5d, 0x62, 0x63, 0x66, 0x6e, 0x7f, 0x91, + 0x98, 0x99, 0xa0, 0xa8, 0xa8, 0xa2, 0x9a, 0x92, 0x8b, 0x84, 0x7a, + 0x72, 0x6e, 0x6c, 0x71, 0x74, 0x75, 0x7a, 0x82, 0x89, 0x8b, 0x8b, + 0x8b, 0x88, 0x83, 0x7b, 0x71, 0x6a, 0x63, 0x5c, 0x55, 0x51, 0x4f, + 0x4e, 0x4e, 0x4d, 0x4b, 0x4f, 0x5e, 0x75, 0x93, 0xa7, 0xa7, 0xa7, + 0xb1, 0xbb, 0xaf, 0x95, 0x87, 0x82, 0x7c, 0x73, 0x68, 0x62, 0x63, + 0x6d, 0x7c, 0x83, 0x86, 0x8c, 0x97, 0xa1, 0xa1, 0x9a, 0x94, 0x91, + 0x8e, 0x88, 0x7e, 0x76, 0x74, 0x75, 0x76, 0x76, 0x78, 0x7b, 0x82, + 0x87, 0x8a, 0x8c, 0x8d, 0x8e, 0x8d, 0x89, 0x80, 0x77, 0x71, 0x6b, + 0x65, 0x5e, 0x59, 0x58, 0x58, 0x57, 0x55, 0x55, 0x58, 0x57, 0x55, + 0x53, 0x56, 0x66, 0x7c, 0x99, 0xab, 0xa9, 0xa2, 0xa5, 0xac, 0xa7, + 0x94, 0x84, 0x7d, 0x79, 0x77, 0x75, 0x6e, 0x69, 0x6e, 0x7c, 0x8a, + 0x8e, 0x8e, 0x90, 0x98, 0x9f, 0x9d, 0x93, 0x89, 0x85, 0x86, 0x83, + 0x7d, 0x76, 0x74, 0x77, 0x7c, 0x7f, 0x7e, 0x7f, 0x84, 0x8c, 0x8f, + 0x8c, 0x88, 0x85, 0x84, 0x82, 0x7b, 0x72, 0x6b, 0x67, 0x67, 0x67, + 0x65, 0x62, 0x61, 0x61, 0x61, 0x62, 0x60, 0x60, 0x62, 0x61, 0x60, + 0x5d, 0x5b, 0x5e, 0x6a, 0x88, 0xa8, 0xb0, 0xa3, 0x97, 0x9d, 0xab, + 0xa8, 0x93, 0x81, 0x7a, 0x7b, 0x7b, 0x78, 0x75, 0x75, 0x76, 0x7e, + 0x8b, 0x95, 0x97, 0x93, 0x91, 0x95, 0x95, 0x8f, 0x85, 0x7e, 0x7b, + 0x78, 0x77, 0x78, 0x77, 0x76, 0x77, 0x7d, 0x85, 0x89, 0x89, 0x8c, + 0x92, 0x93, 0x8f, 0x88, 0x83, 0x7f, 0x79, 0x73, 0x6e, 0x6b, 0x69, + 0x67, 0x65, 0x65, 0x64, 0x64, 0x64, 0x61, 0x60, 0x60, 0x61, 0x62, + 0x62, 0x60, 0x5e, 0x5e, 0x64, 0x6c, 0x73, 0x77, 0x80, 0x96, 0xae, + 0xb2, 0xa3, 0x94, 0x93, 0x97, 0x91, 0x82, 0x79, 0x79, 0x7a, 0x7a, + 0x7b, 0x81, 0x89, 0x8d, 0x8e, 0x90, 0x93, 0x93, 0x8f, 0x88, 0x83, + 0x7d, 0x76, 0x70, 0x70, 0x74, 0x77, 0x77, 0x78, 0x7e, 0x88, 0x91, + 0x95, 0x94, 0x91, 0x8d, 0x8b, 0x88, 0x84, 0x7f, 0x79, 0x74, 0x71, + 0x71, 0x73, 0x75, 0x75, 0x76, 0x79, 0x7c, 0x7b, 0x77, 0x73, 0x70, + 0x6b, 0x65, 0x5f, 0x5b, 0x5a, 0x5d, 0x61, 0x64, 0x62, 0x5d, 0x59, + 0x56, 0x54, 0x52, 0x53, 0x5d, 0x76, 0x9c, 0xbb, 0xc1, 0xb4, 0xa6, + 0xa4, 0xa8, 0xa1, 0x91, 0x81, 0x77, 0x73, 0x72, 0x72, 0x74, 0x79, + 0x7f, 0x84, 0x8a, 0x93, 0x9b, 0x9c, 0x95, 0x8d, 0x89, 0x85, 0x7f, + 0x77, 0x70, 0x6c, 0x6b, 0x6c, 0x70, 0x75, 0x7a, 0x7f, 0x85, 0x8c, + 0x92, 0x95, 0x93, 0x8f, 0x8a, 0x86, 0x83, 0x80, 0x7c, 0x79, 0x78, + 0x79, 0x7b, 0x7c, 0x7a, 0x7a, 0x7c, 0x7e, 0x7d, 0x79, 0x76, 0x76, + 0x74, 0x72, 0x6e, 0x6c, 0x6d, 0x6d, 0x6b, 0x68, 0x66, 0x68, 0x6a, + 0x6a, 0x66, 0x65, 0x69, 0x6b, 0x67, 0x62, 0x61, 0x6a, 0x87, 0xaf, + 0xc2, 0xb7, 0xa0, 0x94, 0x9e, 0xa5, 0x98, 0x83, 0x74, 0x6e, 0x6e, + 0x73, 0x7d, 0x87, 0x85, 0x82, 0x89, 0x93, 0x95, 0x8e, 0x86, 0x87, + 0x8b, 0x86, 0x7d, 0x77, 0x72, 0x6d, 0x6a, 0x6c, 0x76, 0x7e, 0x7f, + 0x7f, 0x83, 0x8b, 0x90, 0x8f, 0x8b, 0x89, 0x88, 0x86, 0x85, 0x82, + 0x80, 0x7e, 0x7c, 0x7c, 0x7e, 0x81, 0x82, 0x81, 0x82, 0x84, 0x82, + 0x7d, 0x78, 0x75, 0x74, 0x74, 0x73, 0x74, 0x75, 0x74, 0x74, 0x73, + 0x73, 0x73, 0x71, 0x6f, 0x6e, 0x6b, 0x68, 0x66, 0x68, 0x6a, 0x68, + 0x68, 0x6a, 0x69, 0x67, 0x6a, 0x78, 0x9b, 0xc0, 0xc5, 0xb1, 0x9b, + 0x93, 0x92, 0x89, 0x7e, 0x76, 0x6f, 0x6a, 0x71, 0x7f, 0x8c, 0x8f, + 0x8b, 0x8e, 0x97, 0x98, 0x92, 0x8a, 0x81, 0x78, 0x73, 0x74, 0x75, + 0x73, 0x75, 0x7b, 0x81, 0x84, 0x85, 0x85, 0x84, 0x82, 0x7f, 0x7f, + 0x80, 0x81, 0x81, 0x7f, 0x7d, 0x7e, 0x83, 0x8c, 0x91, 0x8d, 0x89, + 0x86, 0x83, 0x81, 0x7f, 0x7e, 0x7c, 0x79, 0x79, 0x7b, 0x7c, 0x7c, + 0x7a, 0x7a, 0x79, 0x77, 0x75, 0x75, 0x75, 0x74, 0x75, 0x79, 0x7a, + 0x77, 0x74, 0x73, 0x72, 0x6e, 0x6c, 0x6c, 0x6b, 0x6b, 0x6c, 0x6d, + 0x6d, 0x6e, 0x71, 0x73, 0x76, 0x8a, 0xab, 0xbd, 0xb5, 0xa2, 0x95, + 0x8d, 0x84, 0x7c, 0x77, 0x6f, 0x6b, 0x74, 0x84, 0x8d, 0x8d, 0x8f, + 0x94, 0x94, 0x8f, 0x8d, 0x87, 0x7b, 0x73, 0x75, 0x79, 0x79, 0x78, + 0x7b, 0x7e, 0x81, 0x83, 0x84, 0x82, 0x80, 0x80, 0x81, 0x7f, 0x7c, + 0x7c, 0x7c, 0x7a, 0x7c, 0x81, 0x85, 0x88, 0x8f, 0x90, 0x8a, 0x88, + 0x86, 0x82, 0x7d, 0x7a, 0x7a, 0x79, 0x79, 0x7d, 0x7d, 0x7b, 0x7a, + 0x7b, 0x7c, 0x7b, 0x7c, 0x7d, 0x7c, 0x7a, 0x79, 0x77, 0x75, 0x72, + 0x71, 0x71, 0x70, 0x70, 0x71, 0x71, 0x6f, 0x6d, 0x6c, 0x6c, 0x6b, + 0x6d, 0x6e, 0x6f, 0x72, 0x73, 0x7b, 0x91, 0xb0, 0xbd, 0xb1, 0x9e, + 0x8b, 0x7f, 0x7d, 0x7f, 0x7a, 0x70, 0x74, 0x80, 0x8c, 0x95, 0x97, + 0x94, 0x8e, 0x89, 0x89, 0x84, 0x7e, 0x78, 0x73, 0x75, 0x7c, 0x84, + 0x86, 0x84, 0x86, 0x89, 0x87, 0x83, 0x7f, 0x7a, 0x73, 0x74, 0x77, + 0x79, 0x7b, 0x7c, 0x7e, 0x85, 0x8b, 0x8c, 0x88, 0x84, 0x80, 0x7e, + 0x7e, 0x81, 0x88, 0x89, 0x84, 0x86, 0x86, 0x84, 0x81, 0x7c, 0x77, + 0x74, 0x77, 0x7c, 0x7f, 0x80, 0x7e, 0x7c, 0x7b, 0x7c, 0x7b, 0x78, + 0x75, 0x70, 0x6f, 0x73, 0x75, 0x76, 0x75, 0x75, 0x74, 0x72, 0x73, + 0x6f, 0x6b, 0x6c, 0x6b, 0x6c, 0x6c, 0x6c, 0x6e, 0x6f, 0x7e, 0xa1, + 0xbc, 0xbe, 0xad, 0x95, 0x7e, 0x75, 0x7b, 0x7f, 0x79, 0x77, 0x7d, + 0x86, 0x93, 0x9c, 0x97, 0x8d, 0x87, 0x84, 0x7f, 0x7f, 0x7e, 0x78, + 0x76, 0x7b, 0x81, 0x86, 0x8a, 0x8b, 0x85, 0x7e, 0x7d, 0x7b, 0x79, + 0x78, 0x76, 0x73, 0x73, 0x7c, 0x86, 0x8a, 0x89, 0x87, 0x83, 0x81, + 0x80, 0x7d, 0x77, 0x78, 0x80, 0x86, 0x8b, 0x90, 0x8d, 0x84, 0x7f, + 0x80, 0x7f, 0x7f, 0x7f, 0x7b, 0x78, 0x7a, 0x7e, 0x7e, 0x7e, 0x7b, + 0x75, 0x75, 0x78, 0x7a, 0x7c, 0x7a, 0x77, 0x75, 0x76, 0x76, 0x75, + 0x75, 0x75, 0x75, 0x76, 0x75, 0x73, 0x72, 0x72, 0x72, 0x70, 0x6c, + 0x69, 0x6a, 0x6f, 0x7f, 0x9c, 0xb6, 0xb9, 0xac, 0x96, 0x83, 0x7a, + 0x7a, 0x7f, 0x7e, 0x7d, 0x7f, 0x85, 0x8f, 0x96, 0x94, 0x8e, 0x87, + 0x81, 0x7f, 0x80, 0x7f, 0x7b, 0x7a, 0x79, 0x7a, 0x80, 0x86, 0x88, + 0x89, 0x86, 0x80, 0x7b, 0x7a, 0x7a, 0x79, 0x79, 0x79, 0x7a, 0x80, + 0x86, 0x86, 0x82, 0x7f, 0x7d, 0x7e, 0x83, 0x8a, 0x8c, 0x8b, 0x8a, + 0x87, 0x81, 0x7d, 0x7b, 0x7b, 0x7c, 0x7e, 0x80, 0x7f, 0x80, 0x7e, + 0x7a, 0x77, 0x73, 0x72, 0x73, 0x75, 0x79, 0x7c, 0x7c, 0x79, 0x77, + 0x76, 0x76, 0x78, 0x79, 0x79, 0x77, 0x75, 0x75, 0x75, 0x76, 0x77, + 0x75, 0x74, 0x74, 0x75, 0x74, 0x73, 0x71, 0x6d, 0x6a, 0x6b, 0x7a, + 0x99, 0xb0, 0xb6, 0xb1, 0x9c, 0x85, 0x7b, 0x7e, 0x86, 0x89, 0x86, + 0x81, 0x7b, 0x7f, 0x8a, 0x92, 0x96, 0x8f, 0x84, 0x7d, 0x7d, 0x83, + 0x88, 0x88, 0x81, 0x79, 0x75, 0x79, 0x81, 0x87, 0x88, 0x82, 0x7c, + 0x78, 0x79, 0x7d, 0x80, 0x7f, 0x7c, 0x7a, 0x7a, 0x7c, 0x7f, 0x82, + 0x81, 0x80, 0x82, 0x84, 0x87, 0x89, 0x87, 0x82, 0x7d, 0x7b, 0x7b, + 0x7d, 0x80, 0x80, 0x7f, 0x7c, 0x79, 0x77, 0x77, 0x79, 0x79, 0x79, + 0x79, 0x79, 0x78, 0x79, 0x7a, 0x7a, 0x7a, 0x7a, 0x79, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x79, 0x7c, 0x7c, 0x7d, 0x7e, 0x7b, 0x79, 0x78, + 0x79, 0x79, 0x78, 0x77, 0x72, 0x6b, 0x66, 0x65, 0x76, 0x94, 0xa9, + 0xb6, 0xb3, 0x9e, 0x88, 0x7d, 0x7e, 0x85, 0x8b, 0x8e, 0x88, 0x81, + 0x7f, 0x81, 0x87, 0x8e, 0x92, 0x90, 0x87, 0x7f, 0x7c, 0x7f, 0x84, + 0x88, 0x86, 0x82, 0x7c, 0x78, 0x78, 0x7b, 0x7e, 0x80, 0x80, 0x7d, + 0x7a, 0x7a, 0x7b, 0x7e, 0x83, 0x84, 0x83, 0x80, 0x7d, 0x7e, 0x80, + 0x84, 0x86, 0x86, 0x83, 0x7e, 0x7c, 0x7c, 0x80, 0x84, 0x84, 0x80, + 0x7a, 0x74, 0x72, 0x75, 0x7a, 0x7d, 0x7e, 0x7b, 0x76, 0x73, 0x74, + 0x76, 0x79, 0x7c, 0x7c, 0x79, 0x76, 0x76, 0x78, 0x7b, 0x7d, 0x7f, + 0x7d, 0x7a, 0x79, 0x79, 0x79, 0x7b, 0x7c, 0x7b, 0x7a, 0x79, 0x78, + 0x77, 0x76, 0x74, 0x72, 0x6f, 0x6c, 0x6e, 0x7a, 0x8b, 0x9a, 0xa5, + 0xa7, 0x9f, 0x94, 0x8b, 0x87, 0x87, 0x8c, 0x8e, 0x8c, 0x86, 0x80, + 0x7c, 0x7e, 0x84, 0x8b, 0x8e, 0x8d, 0x89, 0x83, 0x81, 0x80, 0x81, + 0x83, 0x83, 0x81, 0x7d, 0x79, 0x76, 0x75, 0x78, 0x7b, 0x7e, 0x80, + 0x80, 0x7f, 0x7e, 0x7d, 0x7d, 0x7e, 0x7f, 0x7f, 0x7e, 0x7d, 0x7a, + 0x79, 0x7b, 0x7f, 0x84, 0x88, 0x8a, 0x89, 0x86, 0x83, 0x80, 0x7e, + 0x7e, 0x7f, 0x7d, 0x7c, 0x7a, 0x78, 0x77, 0x79, 0x7a, 0x7b, 0x7b, + 0x7b, 0x7b, 0x7c, 0x7d, 0x7e, 0x7d, 0x7b, 0x79, 0x78, 0x77, 0x77, + 0x79, 0x7a, 0x7b, 0x7b, 0x7b, 0x7b, 0x7c, 0x7c, 0x7c, 0x7b, 0x7b, + 0x7a, 0x79, 0x77, 0x76, 0x75, 0x75, 0x76, 0x77, 0x7e, 0x86, 0x8c, + 0x93, 0x95, 0x93, 0x91, 0x8e, 0x8c, 0x8c, 0x8e, 0x90, 0x8e, 0x8b, + 0x87, 0x82, 0x81, 0x81, 0x83, 0x86, 0x87, 0x87, 0x86, 0x85, 0x85, + 0x84, 0x84, 0x85, 0x84, 0x82, 0x7f, 0x7c, 0x79, 0x78, 0x78, 0x79, + 0x7b, 0x7d, 0x7e, 0x7e, 0x7d, 0x7d, 0x7e, 0x7f, 0x80, 0x7f, 0x7f, + 0x7d, 0x7b, 0x7b, 0x7c, 0x7c, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x80, 0x81, 0x82, 0x82, 0x82, 0x81, 0x80, 0x7e, 0x7e, 0x7e, 0x7e, + 0x7e, 0x7d, 0x7d, 0x7c, 0x7b, 0x7b, 0x7b, 0x7c, 0x7c, 0x7c, 0x7c, + 0x7b, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, + 0x7c, 0x7c, 0x7d, 0x7d, 0x7e, 0x7e, 0x7e, 0x7d, 0x7d, 0x7d, 0x7e, + 0x80, 0x83, 0x85, 0x86, 0x86, 0x86, 0x86, 0x86, 0x88, 0x89, 0x8a, + 0x8b, 0x8b, 0x8b, 0x8a, 0x89, 0x88, 0x88, 0x88, 0x89, 0x88, 0x87, + 0x86, 0x85, 0x84, 0x83, 0x83, 0x82, 0x82, 0x81, 0x81, 0x80, 0x80, + 0x80, 0x80, 0x81, 0x81, 0x81, 0x81, 0x80, 0x7f, 0x7f, 0x7e, 0x7e, + 0x7e, 0x7e, 0x7d, 0x7d, 0x7c, 0x7b, 0x7a, 0x79, 0x79, 0x79, 0x79, + 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x7a, 0x7a, 0x7b, 0x7b, 0x7b, + 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7a, 0x7a, 0x7a, 0x79, + 0x79, 0x79, 0x7a, 0x79, 0x7a, 0x7a, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, + 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7c, 0x7c, 0x7d, + 0x7d, 0x7d, 0x7e, 0x7e, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7e, 0x7e, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, 0x7e, 0x7f, 0x80, 0x80, 0x81, 0x80, + 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, + 0x80, 0x81, 0x82, 0x82, 0x82, 0x82, 0x81, 0x81, 0x82, 0x83, 0x83, + 0x83, 0x84, 0x84, 0x83, 0x84, 0x84, 0x84, 0x85, 0x85, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x83, 0x82, 0x81, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x7f, 0x7e, 0x7d, 0x7d, 0x7c, 0x7c, 0x7c, 0x7d, + 0x7d, 0x7c, 0x7b, 0x7b, 0x7a, 0x7b, 0x7c, 0x7d, 0x7d, 0x7e, 0x7e, + 0x7e, 0x7e, 0x7e, 0x7e, 0x7d, 0x7d, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, + 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7d, 0x7d, 0x7d, 0x7e, 0x7e, + 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x81, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, 0x80, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x80, 0x80, + 0x80, 0x80, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7e, 0x7e, 0x7d, 0x7e, 0x7e, + 0x7e, 0x7e, 0x7e, 0x7d, 0x7d, 0x7c, 0x7c, 0x7d, 0x7e, 0x7e, 0x7f, + 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x7f, + 0x7e, 0x7f, 0x7f, 0x80, 0x80, 0x81, 0x80, 0x80, 0x7f, 0x7f, 0x7f, + 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7e, 0x7e, 0x7f, + 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x81, 0x81, 0x81, 0x81, 0x80, 0x7f, 0x7f, + 0x7f, 0x80, 0x80, 0x81, 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x81, 0x81, 0x81, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x80, 0x80, + 0x81, 0x81, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x80, + 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, + 0x7f, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, + 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, + }, + { // 1 + 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x80, + 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, + 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, + 0x80, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x84, + 0x8a, 0x8f, 0x93, 0x94, 0x95, 0x95, 0x94, 0x91, 0x8f, 0x8d, 0x8c, + 0x8b, 0x8a, 0x8a, 0x89, 0x87, 0x85, 0x83, 0x82, 0x80, 0x80, 0x81, + 0x82, 0x82, 0x81, 0x7f, 0x7e, 0x7d, 0x7c, 0x7a, 0x79, 0x79, 0x78, + 0x77, 0x77, 0x79, 0x7b, 0x7d, 0x7e, 0x7f, 0x7e, 0x7e, 0x7d, 0x7d, + 0x7c, 0x7c, 0x7c, 0x7b, 0x7b, 0x7a, 0x79, 0x79, 0x78, 0x77, 0x77, + 0x77, 0x78, 0x77, 0x76, 0x75, 0x75, 0x75, 0x76, 0x75, 0x75, 0x74, + 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x75, 0x77, 0x7a, 0x7e, 0x84, + 0x8a, 0x91, 0x98, 0x9c, 0x9e, 0x9f, 0x9d, 0x9a, 0x97, 0x94, 0x93, + 0x92, 0x91, 0x90, 0x8e, 0x8a, 0x85, 0x80, 0x7d, 0x7a, 0x7a, 0x7a, + 0x7c, 0x7f, 0x81, 0x83, 0x83, 0x83, 0x82, 0x81, 0x7f, 0x7d, 0x7c, + 0x7c, 0x7c, 0x7d, 0x7d, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, 0x7e, + 0x7d, 0x7c, 0x7b, 0x7a, 0x79, 0x77, 0x74, 0x72, 0x71, 0x70, 0x70, + 0x70, 0x71, 0x70, 0x6e, 0x6c, 0x6a, 0x6a, 0x6b, 0x6c, 0x6d, 0x6d, + 0x6a, 0x68, 0x6a, 0x6f, 0x78, 0x85, 0x92, 0x9f, 0xa7, 0xab, 0xac, + 0xaa, 0xa7, 0xa2, 0x9c, 0x98, 0x94, 0x92, 0x91, 0x8f, 0x8c, 0x87, + 0x81, 0x7b, 0x76, 0x74, 0x74, 0x77, 0x7a, 0x7e, 0x81, 0x84, 0x85, + 0x84, 0x84, 0x82, 0x81, 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, + 0x7f, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7d, 0x7b, 0x7a, 0x79, 0x77, + 0x76, 0x75, 0x73, 0x72, 0x71, 0x6f, 0x6d, 0x6b, 0x69, 0x69, 0x6a, + 0x6a, 0x6a, 0x6b, 0x6b, 0x69, 0x67, 0x69, 0x6d, 0x75, 0x81, 0x8f, + 0x9c, 0xa6, 0xab, 0xad, 0xac, 0xa9, 0xa4, 0x9d, 0x97, 0x92, 0x8f, + 0x8d, 0x8c, 0x8a, 0x88, 0x85, 0x81, 0x7e, 0x7c, 0x7d, 0x7f, 0x81, + 0x83, 0x84, 0x84, 0x82, 0x80, 0x7e, 0x7d, 0x7e, 0x7f, 0x82, 0x85, + 0x87, 0x87, 0x86, 0x84, 0x81, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x7f, + 0x7d, 0x77, 0x71, 0x69, 0x62, 0x5b, 0x56, 0x53, 0x52, 0x52, 0x52, + 0x52, 0x52, 0x51, 0x4f, 0x50, 0x59, 0x66, 0x7b, 0x92, 0xa8, 0xb9, + 0xbe, 0xbb, 0xb1, 0x9f, 0x8c, 0x7a, 0x6e, 0x69, 0x6c, 0x77, 0x85, + 0x94, 0xa1, 0xa7, 0xa7, 0xa0, 0x97, 0x8b, 0x82, 0x7c, 0x78, 0x78, + 0x79, 0x7c, 0x80, 0x82, 0x84, 0x86, 0x87, 0x87, 0x87, 0x85, 0x84, + 0x82, 0x81, 0x80, 0x82, 0x83, 0x86, 0x87, 0x85, 0x82, 0x7c, 0x73, + 0x6a, 0x62, 0x5d, 0x5a, 0x59, 0x5b, 0x5c, 0x5d, 0x5c, 0x5c, 0x5b, + 0x57, 0x50, 0x4e, 0x54, 0x63, 0x7b, 0x95, 0xaf, 0xbe, 0xbe, 0xb9, + 0xa8, 0x92, 0x7d, 0x6c, 0x64, 0x66, 0x71, 0x81, 0x94, 0xa3, 0xac, + 0xab, 0xa3, 0x96, 0x87, 0x7a, 0x74, 0x72, 0x76, 0x7c, 0x81, 0x86, + 0x88, 0x86, 0x83, 0x80, 0x7f, 0x80, 0x82, 0x85, 0x89, 0x8b, 0x8b, + 0x8a, 0x88, 0x85, 0x82, 0x7f, 0x7c, 0x79, 0x76, 0x72, 0x6f, 0x6c, + 0x6a, 0x67, 0x63, 0x61, 0x5e, 0x5c, 0x5b, 0x5a, 0x57, 0x55, 0x52, + 0x51, 0x5b, 0x6a, 0x83, 0x9e, 0xb3, 0xbf, 0xbd, 0xae, 0x96, 0x7d, + 0x69, 0x5f, 0x63, 0x72, 0x87, 0x9c, 0xaa, 0xaf, 0xaa, 0x9c, 0x8d, + 0x7d, 0x74, 0x71, 0x76, 0x7f, 0x87, 0x8d, 0x8d, 0x8a, 0x83, 0x7a, + 0x75, 0x72, 0x75, 0x7c, 0x84, 0x8e, 0x93, 0x95, 0x93, 0x8e, 0x88, + 0x81, 0x7d, 0x7a, 0x79, 0x7a, 0x7a, 0x7a, 0x78, 0x76, 0x72, 0x6d, + 0x67, 0x62, 0x5e, 0x5c, 0x5b, 0x59, 0x58, 0x57, 0x55, 0x54, 0x56, + 0x61, 0x71, 0x89, 0xa3, 0xb4, 0xbc, 0xb5, 0xa3, 0x8b, 0x74, 0x66, + 0x64, 0x70, 0x83, 0x97, 0xa6, 0xab, 0xa7, 0x9a, 0x8b, 0x7e, 0x76, + 0x76, 0x7b, 0x83, 0x8a, 0x8c, 0x8a, 0x85, 0x7e, 0x79, 0x76, 0x78, + 0x7a, 0x7e, 0x82, 0x85, 0x89, 0x8a, 0x8a, 0x8a, 0x89, 0x88, 0x87, + 0x87, 0x87, 0x86, 0x85, 0x81, 0x7c, 0x77, 0x73, 0x71, 0x71, 0x72, + 0x73, 0x71, 0x6c, 0x66, 0x5d, 0x56, 0x51, 0x4d, 0x4b, 0x4c, 0x4f, + 0x5f, 0x75, 0x8c, 0xa9, 0xb7, 0xb9, 0xaf, 0x96, 0x7e, 0x68, 0x61, + 0x68, 0x7c, 0x95, 0xa7, 0xb1, 0xad, 0x9e, 0x8c, 0x7a, 0x70, 0x70, + 0x78, 0x85, 0x8f, 0x93, 0x8f, 0x85, 0x7b, 0x73, 0x73, 0x78, 0x80, + 0x86, 0x87, 0x83, 0x7d, 0x79, 0x7c, 0x83, 0x8e, 0x96, 0x9a, 0x97, + 0x8d, 0x82, 0x79, 0x74, 0x76, 0x7b, 0x81, 0x85, 0x85, 0x81, 0x79, + 0x71, 0x69, 0x64, 0x61, 0x61, 0x62, 0x62, 0x60, 0x5d, 0x58, 0x54, + 0x4f, 0x54, 0x66, 0x7b, 0x95, 0xac, 0xb8, 0xb5, 0xa3, 0x8b, 0x75, + 0x6a, 0x6e, 0x7d, 0x93, 0xa2, 0xa7, 0xa1, 0x93, 0x85, 0x7b, 0x7b, + 0x80, 0x87, 0x8e, 0x8e, 0x89, 0x82, 0x7a, 0x78, 0x7a, 0x80, 0x87, + 0x8b, 0x8a, 0x82, 0x77, 0x6d, 0x67, 0x68, 0x72, 0x84, 0x96, 0xa3, + 0xa7, 0x9e, 0x8f, 0x7e, 0x72, 0x71, 0x79, 0x85, 0x90, 0x94, 0x90, + 0x85, 0x77, 0x6b, 0x65, 0x65, 0x67, 0x6c, 0x6f, 0x6f, 0x6b, 0x65, + 0x5f, 0x5a, 0x58, 0x57, 0x57, 0x5c, 0x68, 0x78, 0x89, 0xa2, 0xb2, + 0xae, 0xa6, 0x94, 0x81, 0x78, 0x77, 0x7f, 0x8c, 0x95, 0x99, 0x97, + 0x90, 0x88, 0x85, 0x83, 0x83, 0x83, 0x81, 0x7f, 0x7e, 0x7e, 0x82, + 0x87, 0x8a, 0x89, 0x82, 0x78, 0x6f, 0x6a, 0x6d, 0x76, 0x81, 0x8a, + 0x8d, 0x8a, 0x83, 0x7c, 0x7d, 0x83, 0x8d, 0x96, 0x96, 0x90, 0x88, + 0x81, 0x7f, 0x81, 0x83, 0x83, 0x80, 0x7b, 0x76, 0x74, 0x75, 0x77, + 0x77, 0x75, 0x73, 0x6f, 0x6d, 0x6e, 0x6c, 0x6b, 0x68, 0x68, 0x67, + 0x65, 0x65, 0x60, 0x5e, 0x5e, 0x76, 0x9b, 0xaf, 0xbf, 0xb7, 0x9d, + 0x7f, 0x65, 0x62, 0x70, 0x8a, 0x9c, 0xa0, 0x9d, 0x8a, 0x7f, 0x7f, + 0x81, 0x8c, 0x91, 0x91, 0x8a, 0x7d, 0x73, 0x6f, 0x76, 0x80, 0x88, + 0x8e, 0x8c, 0x85, 0x7b, 0x72, 0x6e, 0x6e, 0x74, 0x7d, 0x85, 0x8b, + 0x89, 0x85, 0x81, 0x7d, 0x7e, 0x83, 0x8a, 0x8f, 0x92, 0x8c, 0x82, + 0x7b, 0x78, 0x7b, 0x81, 0x87, 0x87, 0x83, 0x7b, 0x75, 0x72, 0x73, + 0x76, 0x78, 0x78, 0x76, 0x75, 0x74, 0x72, 0x72, 0x72, 0x70, 0x6f, + 0x6f, 0x6d, 0x6d, 0x6b, 0x68, 0x62, 0x5c, 0x6c, 0x92, 0xb4, 0xc4, + 0xbf, 0xa3, 0x7c, 0x63, 0x62, 0x76, 0x90, 0x9f, 0x9c, 0x92, 0x85, + 0x7e, 0x84, 0x8d, 0x90, 0x8a, 0x7e, 0x72, 0x6e, 0x75, 0x81, 0x8e, + 0x93, 0x8e, 0x83, 0x7a, 0x77, 0x79, 0x7c, 0x7e, 0x7c, 0x79, 0x77, + 0x7a, 0x7e, 0x83, 0x86, 0x86, 0x83, 0x7e, 0x7a, 0x7a, 0x7d, 0x84, + 0x8c, 0x90, 0x91, 0x8d, 0x84, 0x7d, 0x79, 0x7a, 0x7e, 0x83, 0x86, + 0x85, 0x81, 0x7e, 0x7b, 0x79, 0x78, 0x78, 0x76, 0x74, 0x73, 0x72, + 0x71, 0x71, 0x72, 0x74, 0x75, 0x76, 0x74, 0x70, 0x6c, 0x68, 0x66, + 0x64, 0x64, 0x64, 0x6a, 0x84, 0xa7, 0xbf, 0xc1, 0xac, 0x89, 0x6d, + 0x64, 0x6e, 0x83, 0x91, 0x91, 0x88, 0x82, 0x83, 0x8a, 0x91, 0x92, + 0x8a, 0x7e, 0x77, 0x77, 0x7d, 0x84, 0x88, 0x88, 0x85, 0x82, 0x82, + 0x84, 0x82, 0x7c, 0x75, 0x70, 0x71, 0x79, 0x80, 0x85, 0x87, 0x87, + 0x85, 0x85, 0x84, 0x80, 0x7b, 0x78, 0x7b, 0x84, 0x8d, 0x92, 0x90, + 0x87, 0x80, 0x7d, 0x7e, 0x80, 0x81, 0x80, 0x7e, 0x7b, 0x7b, 0x7d, + 0x7d, 0x79, 0x75, 0x72, 0x71, 0x72, 0x73, 0x73, 0x72, 0x73, 0x73, + 0x74, 0x75, 0x73, 0x70, 0x6e, 0x6d, 0x6d, 0x6d, 0x6e, 0x6d, 0x6d, + 0x70, 0x70, 0x6d, 0x72, 0x88, 0xa5, 0xb6, 0xaf, 0x9a, 0x86, 0x7d, + 0x83, 0x8b, 0x8d, 0x87, 0x81, 0x83, 0x8c, 0x94, 0x92, 0x8a, 0x83, + 0x80, 0x81, 0x81, 0x7d, 0x77, 0x75, 0x7d, 0x86, 0x8a, 0x88, 0x84, + 0x81, 0x81, 0x80, 0x7d, 0x78, 0x74, 0x74, 0x78, 0x7c, 0x80, 0x84, + 0x85, 0x86, 0x88, 0x87, 0x84, 0x81, 0x83, 0x8a, 0x90, 0x8d, 0x84, + 0x7f, 0x7f, 0x80, 0x82, 0x82, 0x80, 0x7f, 0x7f, 0x7e, 0x7d, 0x79, + 0x76, 0x75, 0x76, 0x75, 0x74, 0x72, 0x70, 0x71, 0x72, 0x72, 0x72, + 0x72, 0x72, 0x72, 0x73, 0x74, 0x71, 0x6d, 0x6c, 0x6d, 0x72, 0x74, + 0x72, 0x6f, 0x6f, 0x74, 0x7b, 0x83, 0x8b, 0x8d, 0x91, 0x9b, 0xa0, + 0x9e, 0x99, 0x93, 0x90, 0x8d, 0x8a, 0x87, 0x86, 0x87, 0x89, 0x89, + 0x88, 0x84, 0x80, 0x80, 0x7f, 0x80, 0x82, 0x84, 0x83, 0x80, 0x7e, + 0x7e, 0x7f, 0x7d, 0x7a, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x7b, + 0x7d, 0x7e, 0x7f, 0x81, 0x81, 0x81, 0x85, 0x89, 0x8a, 0x87, 0x86, + 0x89, 0x8b, 0x8a, 0x87, 0x86, 0x85, 0x82, 0x81, 0x7f, 0x7f, 0x80, + 0x80, 0x7e, 0x7a, 0x77, 0x76, 0x73, 0x73, 0x74, 0x75, 0x75, 0x74, + 0x73, 0x73, 0x74, 0x74, 0x72, 0x71, 0x70, 0x6f, 0x6f, 0x6f, 0x6f, + 0x6f, 0x6f, 0x72, 0x72, 0x72, 0x70, 0x6f, 0x72, 0x74, 0x74, 0x75, + 0x75, 0x77, 0x80, 0x86, 0x83, 0x88, 0x93, 0x97, 0x96, 0x97, 0x99, + 0x9e, 0x9e, 0x9b, 0x9b, 0x9c, 0x9a, 0x99, 0x96, 0x90, 0x8b, 0x89, + 0x85, 0x82, 0x80, 0x7e, 0x7f, 0x7e, 0x7b, 0x79, 0x7a, 0x7a, 0x78, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x78, 0x79, 0x78, 0x78, + 0x7b, 0x7d, 0x80, 0x85, 0x88, 0x86, 0x89, 0x91, 0x90, 0x8b, 0x8a, + 0x8e, 0x8f, 0x8c, 0x87, 0x85, 0x86, 0x84, 0x7e, 0x7a, 0x75, 0x73, + 0x73, 0x70, 0x6c, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6c, 0x6c, 0x6c, + 0x6e, 0x6f, 0x70, 0x70, 0x71, 0x72, 0x72, 0x73, 0x75, 0x74, 0x72, + 0x73, 0x73, 0x73, 0x74, 0x74, 0x73, 0x74, 0x72, 0x72, 0x74, 0x77, + 0x80, 0x85, 0x82, 0x89, 0x98, 0x98, 0x94, 0x99, 0x9d, 0x9f, 0xa2, + 0x9f, 0x9d, 0xa0, 0x9e, 0x9a, 0x97, 0x91, 0x8d, 0x8d, 0x89, 0x84, + 0x83, 0x83, 0x80, 0x80, 0x7e, 0x7b, 0x7b, 0x7a, 0x77, 0x77, 0x77, + 0x75, 0x76, 0x75, 0x74, 0x75, 0x76, 0x75, 0x76, 0x78, 0x79, 0x7b, + 0x7c, 0x7d, 0x80, 0x84, 0x87, 0x89, 0x8a, 0x8d, 0x91, 0x91, 0x8e, + 0x8e, 0x8f, 0x8e, 0x8b, 0x88, 0x85, 0x83, 0x80, 0x7c, 0x78, 0x75, + 0x73, 0x71, 0x6e, 0x6c, 0x6d, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6f, + 0x6e, 0x6e, 0x6e, 0x6f, 0x6f, 0x70, 0x71, 0x73, 0x74, 0x75, 0x75, + 0x77, 0x79, 0x77, 0x76, 0x77, 0x79, 0x79, 0x77, 0x77, 0x79, 0x7b, + 0x81, 0x84, 0x85, 0x8b, 0x93, 0x94, 0x94, 0x97, 0x9a, 0x9e, 0x9f, + 0x9d, 0x9e, 0xa1, 0xa0, 0x9d, 0x9b, 0x97, 0x93, 0x92, 0x8d, 0x87, + 0x86, 0x85, 0x83, 0x81, 0x7f, 0x7d, 0x7d, 0x7b, 0x79, 0x79, 0x78, + 0x75, 0x75, 0x75, 0x73, 0x72, 0x73, 0x72, 0x73, 0x76, 0x77, 0x78, + 0x79, 0x7a, 0x7c, 0x7e, 0x81, 0x83, 0x85, 0x86, 0x8b, 0x8f, 0x8d, + 0x8c, 0x8e, 0x8f, 0x8d, 0x8a, 0x87, 0x86, 0x86, 0x83, 0x7f, 0x7c, + 0x79, 0x78, 0x76, 0x73, 0x71, 0x71, 0x70, 0x6f, 0x6e, 0x6e, 0x6e, + 0x6e, 0x6e, 0x6d, 0x6e, 0x6e, 0x6d, 0x6e, 0x70, 0x70, 0x70, 0x72, + 0x72, 0x74, 0x76, 0x77, 0x78, 0x7a, 0x7a, 0x7a, 0x7b, 0x7a, 0x7b, + 0x7c, 0x7a, 0x7a, 0x80, 0x81, 0x7d, 0x7d, 0x86, 0x8b, 0x86, 0x84, + 0x8c, 0x94, 0x92, 0x8f, 0x92, 0x97, 0x9a, 0x99, 0x97, 0x98, 0x9a, + 0x99, 0x96, 0x93, 0x91, 0x8f, 0x8d, 0x8b, 0x87, 0x85, 0x85, 0x83, + 0x7f, 0x7d, 0x7d, 0x7b, 0x79, 0x78, 0x77, 0x78, 0x77, 0x76, 0x75, + 0x76, 0x76, 0x76, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7b, 0x7c, + 0x7e, 0x80, 0x80, 0x81, 0x85, 0x86, 0x84, 0x85, 0x88, 0x88, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x84, 0x82, 0x82, 0x82, 0x80, 0x7e, 0x7d, + 0x7c, 0x7c, 0x7b, 0x79, 0x78, 0x79, 0x78, 0x77, 0x77, 0x77, 0x76, + 0x77, 0x77, 0x76, 0x76, 0x76, 0x77, 0x77, 0x76, 0x77, 0x78, 0x78, + 0x78, 0x79, 0x79, 0x79, 0x7b, 0x7b, 0x7b, 0x7c, 0x7d, 0x7e, 0x7e, + 0x7f, 0x80, 0x82, 0x84, 0x83, 0x83, 0x85, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x85, 0x85, 0x84, 0x83, 0x81, 0x80, 0x7e, 0x7d, 0x7c, 0x7b, + 0x7a, 0x79, 0x78, 0x78, 0x78, 0x77, 0x77, 0x77, 0x77, 0x77, 0x78, + 0x78, 0x78, 0x79, 0x7a, 0x7a, 0x7a, 0x7b, 0x7c, 0x7c, 0x7b, 0x7b, + 0x7d, 0x7d, 0x7d, 0x7c, 0x7e, 0x7f, 0x7e, 0x7d, 0x7f, 0x80, 0x80, + 0x81, 0x83, 0x84, 0x84, 0x85, 0x87, 0x88, 0x88, 0x8a, 0x8b, 0x8c, + 0x8c, 0x8d, 0x8e, 0x8e, 0x8e, 0x8d, 0x8c, 0x8c, 0x8b, 0x8a, 0x89, + 0x88, 0x87, 0x85, 0x84, 0x83, 0x82, 0x80, 0x7f, 0x7e, 0x7d, 0x7c, + 0x7c, 0x7b, 0x7a, 0x7a, 0x7a, 0x7a, 0x79, 0x79, 0x79, 0x79, 0x79, + 0x79, 0x79, 0x79, 0x7a, 0x7a, 0x7a, 0x7a, 0x7b, 0x7a, 0x7b, 0x7b, + 0x7a, 0x7a, 0x7b, 0x7b, 0x7a, 0x7a, 0x7b, 0x7b, 0x7b, 0x7a, 0x7b, + 0x7b, 0x7d, 0x7c, 0x7c, 0x7d, 0x7e, 0x7e, 0x7d, 0x7e, 0x7f, 0x7f, + 0x80, 0x80, 0x81, 0x81, 0x82, 0x82, 0x81, 0x81, 0x80, 0x80, 0x7e, + 0x7e, 0x7f, 0x7f, 0x80, 0x80, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x80, 0x81, 0x81, 0x81, 0x80, 0x80, 0x81, + 0x81, 0x82, 0x82, 0x83, 0x84, 0x84, 0x85, 0x85, 0x85, 0x85, 0x86, + 0x86, 0x86, 0x85, 0x86, 0x86, 0x85, 0x84, 0x83, 0x83, 0x83, 0x82, + 0x81, 0x81, 0x81, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, + 0x7e, 0x7d, 0x7d, 0x7e, 0x7e, 0x7d, 0x7d, 0x7e, 0x7e, 0x7e, 0x7e, + 0x7e, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x81, 0x81, 0x81, 0x82, 0x82, + 0x83, 0x84, 0x83, 0x84, 0x85, 0x85, 0x85, 0x86, 0x85, 0x85, 0x86, + 0x86, 0x85, 0x85, 0x85, 0x85, 0x84, 0x83, 0x83, 0x83, 0x83, 0x81, + 0x81, 0x80, 0x80, 0x7f, 0x7f, 0x7e, 0x7e, 0x7d, 0x7d, 0x7c, 0x7c, + 0x7c, 0x7b, 0x7b, 0x7a, 0x7a, 0x7b, 0x7b, 0x7b, 0x7a, 0x7a, 0x7b, + 0x7b, 0x7a, 0x7b, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7d, 0x7d, 0x7d, + 0x7d, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x80, + 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, + 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, + 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, + 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x80, + 0x7f, 0x80, 0x7f, 0x80, 0x7f, + }, + { // 2 + 0x80, 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, + 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, + 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, + 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, + 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x80, + 0x80, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, + 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x80, + 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x7f, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x7f, + 0x80, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x80, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x80, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, + 0x80, 0x80, 0x7f, 0x81, 0x80, 0x81, 0x80, 0x7f, 0x80, 0x7e, 0x7d, + 0x80, 0x7e, 0x7e, 0x80, 0x7e, 0x80, 0x7f, 0x80, 0x80, 0x83, 0x7f, + 0x82, 0x7e, 0x83, 0x7e, 0x80, 0x80, 0x7d, 0x83, 0x7b, 0x81, 0x7d, + 0x81, 0x7b, 0x83, 0x7d, 0x7f, 0x83, 0x7b, 0x83, 0x7e, 0x7f, 0x82, + 0x7e, 0x7d, 0x83, 0x7c, 0x83, 0x82, 0x7a, 0x84, 0x80, 0x80, 0x80, + 0x80, 0x7e, 0x7a, 0x84, 0x7a, 0x7f, 0x86, 0x78, 0x80, 0x81, 0x7f, + 0x81, 0x81, 0x84, 0x76, 0x89, 0x7d, 0x7d, 0x8f, 0x7c, 0x87, 0x7f, + 0x82, 0x7a, 0x79, 0x7c, 0x73, 0x7e, 0x7e, 0x7a, 0x81, 0x7f, 0x81, + 0x80, 0x87, 0x81, 0x7f, 0x84, 0x7e, 0x83, 0x7d, 0x84, 0x77, 0x87, + 0x79, 0x7d, 0x82, 0x7c, 0x80, 0x7c, 0x82, 0x7c, 0x82, 0x7e, 0x83, + 0x81, 0x7f, 0x7b, 0x85, 0x7a, 0x85, 0x80, 0x7b, 0x84, 0x7a, 0x81, + 0x7b, 0x83, 0x80, 0x82, 0x7a, 0x82, 0x84, 0x7b, 0x84, 0x7e, 0x82, + 0x84, 0x7d, 0x88, 0x7c, 0x85, 0x81, 0x7e, 0x7f, 0x7e, 0x83, 0x7a, + 0x7e, 0x7d, 0x7d, 0x7d, 0x81, 0x7d, 0x89, 0x7a, 0x82, 0x80, 0x85, + 0x7f, 0x7b, 0x8a, 0x74, 0x85, 0x78, 0x81, 0x7d, 0x81, 0x80, 0x7a, + 0x85, 0x7e, 0x81, 0x7e, 0x83, 0x7d, 0x83, 0x77, 0x81, 0x82, 0x79, + 0x82, 0x83, 0x85, 0x7e, 0x87, 0x7e, 0x82, 0x83, 0x79, 0x80, 0x85, + 0x78, 0x79, 0x8d, 0x7e, 0x7e, 0x87, 0x7e, 0x7a, 0x81, 0x76, 0x7e, + 0x8a, 0x7b, 0x7f, 0x83, 0x7f, 0x7e, 0x84, 0x7a, 0x7d, 0x83, 0x7f, + 0x7d, 0x7e, 0x85, 0x7d, 0x80, 0x7e, 0x7d, 0x80, 0x81, 0x7d, 0x7b, + 0x84, 0x83, 0x7f, 0x7e, 0x81, 0x7e, 0x80, 0x7e, 0x7c, 0x82, 0x7e, + 0x7c, 0x80, 0x84, 0x81, 0x7d, 0x83, 0x80, 0x7d, 0x85, 0x79, 0x7a, + 0x87, 0x7d, 0x79, 0x86, 0x80, 0x7b, 0x86, 0x7f, 0x7f, 0x86, 0x80, + 0x7b, 0x82, 0x7f, 0x79, 0x7c, 0x79, 0x7c, 0x7c, 0x7f, 0x7d, 0x7e, + 0x85, 0x7c, 0x7f, 0x83, 0x83, 0x81, 0x81, 0x82, 0x84, 0x87, 0x81, + 0x7c, 0x83, 0x83, 0x7c, 0x7d, 0x7f, 0x82, 0x7f, 0x7e, 0x7f, 0x80, + 0x80, 0x7f, 0x83, 0x82, 0x82, 0x84, 0x84, 0x83, 0x85, 0x84, 0x80, + 0x80, 0x7f, 0x7a, 0x7a, 0x79, 0x74, 0x77, 0x76, 0x72, 0x74, 0x78, + 0x76, 0x73, 0x7b, 0x7b, 0x76, 0x77, 0x75, 0x6f, 0x6a, 0x6b, 0x69, + 0x63, 0x63, 0x5f, 0x62, 0x60, 0x6e, 0x82, 0x7f, 0x89, 0x99, 0xa2, + 0xa4, 0xa8, 0xa9, 0xa6, 0xa7, 0xa2, 0x9a, 0x92, 0x90, 0x86, 0x7d, + 0x80, 0x7d, 0x7a, 0x7a, 0x7e, 0x85, 0x8e, 0x91, 0x91, 0x99, 0x9e, + 0x9b, 0x97, 0x9b, 0x98, 0x8d, 0x8c, 0x88, 0x7d, 0x7b, 0x7c, 0x78, + 0x75, 0x7a, 0x7a, 0x78, 0x78, 0x75, 0x73, 0x70, 0x6a, 0x64, 0x62, + 0x60, 0x5d, 0x5a, 0x58, 0x59, 0x58, 0x53, 0x55, 0x5d, 0x58, 0x59, + 0x59, 0x6a, 0x8a, 0x87, 0x8a, 0xa1, 0xb3, 0xb3, 0xb1, 0xb8, 0xb1, + 0xb3, 0xaa, 0x9b, 0x94, 0x90, 0x86, 0x76, 0x78, 0x7c, 0x79, 0x77, + 0x7e, 0x88, 0x8d, 0x94, 0x97, 0x9a, 0x9e, 0x9b, 0x95, 0x8e, 0x8c, + 0x8a, 0x83, 0x7f, 0x80, 0x80, 0x7e, 0x7d, 0x82, 0x85, 0x87, 0x86, + 0x84, 0x81, 0x7d, 0x78, 0x71, 0x6a, 0x63, 0x5d, 0x58, 0x55, 0x54, + 0x52, 0x54, 0x57, 0x58, 0x58, 0x59, 0x5e, 0x5c, 0x59, 0x55, 0x73, + 0x8e, 0x89, 0x96, 0xa8, 0xb8, 0xb8, 0xb9, 0xb6, 0xaf, 0xb2, 0xa3, + 0x92, 0x88, 0x86, 0x7b, 0x6d, 0x72, 0x72, 0x72, 0x77, 0x7b, 0x85, + 0x90, 0x9b, 0x9b, 0x9d, 0xa2, 0xa1, 0x98, 0x8f, 0x89, 0x82, 0x7d, + 0x78, 0x75, 0x7a, 0x7e, 0x7f, 0x81, 0x88, 0x8c, 0x8d, 0x8d, 0x89, + 0x84, 0x80, 0x79, 0x72, 0x6d, 0x66, 0x61, 0x5d, 0x5a, 0x58, 0x58, + 0x57, 0x57, 0x5c, 0x5e, 0x5c, 0x58, 0x5c, 0x5c, 0x57, 0x5b, 0x6d, + 0x88, 0x90, 0x99, 0xa9, 0xb5, 0xbb, 0xb8, 0xb4, 0xae, 0xaa, 0xa0, + 0x8e, 0x81, 0x7b, 0x75, 0x6f, 0x6d, 0x70, 0x75, 0x7b, 0x84, 0x8e, + 0x99, 0x9f, 0xa2, 0xa2, 0x9e, 0x97, 0x8e, 0x84, 0x79, 0x73, 0x6f, + 0x65, 0x64, 0x6d, 0x78, 0x81, 0x89, 0x93, 0x9b, 0xa0, 0x9e, 0x99, + 0x95, 0x90, 0x86, 0x7b, 0x71, 0x6d, 0x69, 0x66, 0x63, 0x5f, 0x60, + 0x61, 0x61, 0x61, 0x64, 0x66, 0x65, 0x66, 0x67, 0x65, 0x61, 0x5d, + 0x58, 0x57, 0x55, 0x5a, 0x73, 0x87, 0x92, 0x9e, 0xaa, 0xb6, 0xb7, + 0xb5, 0xad, 0xa4, 0xa4, 0x9a, 0x89, 0x7d, 0x78, 0x73, 0x6d, 0x6e, + 0x6f, 0x75, 0x81, 0x8b, 0x92, 0x98, 0xa1, 0xa4, 0xa0, 0x9d, 0x97, + 0x8d, 0x81, 0x77, 0x6d, 0x65, 0x62, 0x64, 0x68, 0x70, 0x7a, 0x86, + 0x8f, 0x97, 0x9f, 0xa1, 0x9f, 0x99, 0x8f, 0x84, 0x7e, 0x76, 0x6d, + 0x66, 0x66, 0x69, 0x68, 0x6b, 0x6e, 0x71, 0x73, 0x72, 0x71, 0x6c, + 0x6a, 0x66, 0x5e, 0x5b, 0x56, 0x51, 0x50, 0x4f, 0x4b, 0x49, 0x4c, + 0x59, 0x79, 0x95, 0x9d, 0xa3, 0xb1, 0xbd, 0xc0, 0xbc, 0xad, 0xa1, + 0x9c, 0x93, 0x82, 0x6e, 0x67, 0x6b, 0x6c, 0x6a, 0x6e, 0x77, 0x83, + 0x8f, 0x9b, 0x9e, 0x9d, 0xa2, 0xa1, 0x9a, 0x91, 0x87, 0x7b, 0x72, + 0x6c, 0x66, 0x61, 0x64, 0x6c, 0x73, 0x7a, 0x84, 0x8e, 0x97, 0x9c, + 0x9f, 0x9e, 0x9a, 0x91, 0x86, 0x7d, 0x77, 0x73, 0x6f, 0x6b, 0x6b, + 0x70, 0x75, 0x77, 0x75, 0x77, 0x7a, 0x7a, 0x78, 0x73, 0x70, 0x6a, + 0x65, 0x62, 0x5a, 0x53, 0x53, 0x57, 0x57, 0x52, 0x54, 0x59, 0x56, + 0x56, 0x58, 0x7a, 0xaa, 0xad, 0xa3, 0xa5, 0xb8, 0xc0, 0xb9, 0xb2, + 0x91, 0x80, 0x8f, 0x8e, 0x76, 0x5e, 0x63, 0x6c, 0x76, 0x82, 0x7c, + 0x7b, 0x89, 0xa3, 0xac, 0x9b, 0x95, 0x92, 0x92, 0x95, 0x8a, 0x74, + 0x64, 0x6d, 0x76, 0x6f, 0x6a, 0x68, 0x71, 0x7f, 0x89, 0x88, 0x82, + 0x8b, 0x96, 0x98, 0x94, 0x8b, 0x87, 0x84, 0x82, 0x7e, 0x76, 0x74, + 0x74, 0x77, 0x7a, 0x7a, 0x79, 0x7a, 0x7f, 0x83, 0x80, 0x7e, 0x7c, + 0x7a, 0x77, 0x74, 0x6e, 0x66, 0x65, 0x68, 0x66, 0x63, 0x63, 0x62, + 0x65, 0x6b, 0x6c, 0x68, 0x67, 0x6a, 0x6b, 0x67, 0x61, 0x60, 0x73, + 0x94, 0xa3, 0x9f, 0x9b, 0xa1, 0xab, 0xb6, 0xb6, 0xa2, 0x8e, 0x8d, + 0x90, 0x8a, 0x7d, 0x70, 0x68, 0x70, 0x81, 0x82, 0x79, 0x79, 0x85, + 0x95, 0x9e, 0xa0, 0x99, 0x90, 0x91, 0x95, 0x90, 0x83, 0x78, 0x70, + 0x69, 0x6d, 0x71, 0x6d, 0x69, 0x6f, 0x7a, 0x82, 0x87, 0x86, 0x82, + 0x86, 0x91, 0x95, 0x90, 0x85, 0x7e, 0x7d, 0x81, 0x82, 0x7d, 0x78, + 0x74, 0x77, 0x7c, 0x7f, 0x7d, 0x79, 0x7a, 0x7e, 0x7f, 0x7b, 0x77, + 0x73, 0x71, 0x73, 0x72, 0x6f, 0x6d, 0x6d, 0x6e, 0x6d, 0x6b, 0x6a, + 0x6b, 0x6b, 0x6c, 0x6d, 0x6c, 0x6a, 0x69, 0x69, 0x67, 0x66, 0x64, + 0x67, 0x79, 0x8f, 0x9f, 0xa6, 0xa7, 0xa6, 0xa9, 0xb4, 0xb8, 0xae, + 0x9e, 0x91, 0x89, 0x85, 0x85, 0x7d, 0x70, 0x6b, 0x6e, 0x76, 0x7d, + 0x83, 0x86, 0x88, 0x8f, 0x97, 0x9c, 0x9b, 0x96, 0x8e, 0x84, 0x7d, + 0x79, 0x72, 0x6c, 0x67, 0x64, 0x65, 0x6c, 0x76, 0x7b, 0x7f, 0x84, + 0x8a, 0x8f, 0x95, 0x97, 0x94, 0x92, 0x8e, 0x87, 0x83, 0x80, 0x7c, + 0x77, 0x72, 0x6e, 0x6c, 0x71, 0x79, 0x7d, 0x7d, 0x7c, 0x7b, 0x7d, + 0x81, 0x81, 0x7c, 0x75, 0x70, 0x6d, 0x6c, 0x6c, 0x6c, 0x69, 0x68, + 0x69, 0x6a, 0x6d, 0x6f, 0x72, 0x72, 0x71, 0x72, 0x74, 0x75, 0x73, + 0x71, 0x70, 0x6d, 0x6b, 0x6d, 0x7c, 0x92, 0x9f, 0xa7, 0xa8, 0xa5, + 0xa4, 0xa9, 0xb3, 0xb2, 0xa9, 0x9d, 0x8d, 0x81, 0x7d, 0x7e, 0x7c, + 0x79, 0x77, 0x73, 0x74, 0x7c, 0x86, 0x8f, 0x94, 0x97, 0x93, 0x8e, + 0x8c, 0x8b, 0x88, 0x82, 0x7b, 0x70, 0x68, 0x67, 0x67, 0x6b, 0x71, + 0x77, 0x7b, 0x80, 0x86, 0x8c, 0x91, 0x95, 0x94, 0x90, 0x8b, 0x86, + 0x81, 0x7d, 0x79, 0x74, 0x6f, 0x6d, 0x6e, 0x6f, 0x71, 0x75, 0x78, + 0x79, 0x7b, 0x7d, 0x7f, 0x7f, 0x7e, 0x7a, 0x75, 0x73, 0x71, 0x71, + 0x71, 0x6f, 0x6d, 0x6b, 0x6c, 0x6d, 0x6e, 0x70, 0x73, 0x76, 0x78, + 0x79, 0x79, 0x77, 0x75, 0x75, 0x74, 0x74, 0x73, 0x72, 0x72, 0x73, + 0x7d, 0x90, 0x9e, 0xa8, 0xac, 0xaa, 0xa6, 0xa5, 0xaa, 0xac, 0xab, + 0xa5, 0x99, 0x8a, 0x7d, 0x77, 0x75, 0x77, 0x7a, 0x79, 0x76, 0x74, + 0x77, 0x7e, 0x86, 0x8f, 0x93, 0x93, 0x8f, 0x89, 0x83, 0x7e, 0x7c, + 0x7a, 0x78, 0x74, 0x6f, 0x6c, 0x6d, 0x71, 0x78, 0x80, 0x87, 0x8a, + 0x8b, 0x8b, 0x89, 0x88, 0x87, 0x87, 0x85, 0x81, 0x7c, 0x75, 0x70, + 0x6f, 0x70, 0x72, 0x74, 0x77, 0x77, 0x77, 0x77, 0x79, 0x7b, 0x7c, + 0x7d, 0x7c, 0x7a, 0x76, 0x72, 0x70, 0x70, 0x71, 0x72, 0x72, 0x72, + 0x73, 0x74, 0x75, 0x78, 0x7c, 0x7e, 0x7f, 0x7e, 0x7d, 0x7c, 0x79, + 0x79, 0x78, 0x76, 0x75, 0x74, 0x74, 0x73, 0x72, 0x74, 0x7c, 0x89, + 0x97, 0xa3, 0xab, 0xac, 0xa8, 0xa3, 0xa0, 0x9e, 0x9f, 0x9e, 0x9b, + 0x93, 0x88, 0x7f, 0x79, 0x78, 0x7b, 0x7f, 0x83, 0x83, 0x81, 0x80, + 0x80, 0x81, 0x84, 0x85, 0x84, 0x81, 0x7b, 0x75, 0x71, 0x71, 0x73, + 0x77, 0x7a, 0x7b, 0x7b, 0x7b, 0x7c, 0x80, 0x82, 0x84, 0x84, 0x82, + 0x80, 0x7e, 0x7c, 0x7b, 0x7b, 0x7c, 0x7b, 0x7a, 0x79, 0x78, 0x78, + 0x78, 0x78, 0x78, 0x79, 0x79, 0x78, 0x77, 0x76, 0x75, 0x75, 0x76, + 0x76, 0x77, 0x77, 0x77, 0x76, 0x77, 0x77, 0x77, 0x77, 0x77, 0x76, + 0x74, 0x74, 0x75, 0x76, 0x78, 0x79, 0x7a, 0x7a, 0x7b, 0x7b, 0x7c, + 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7c, 0x79, 0x78, 0x7c, 0x85, + 0x8f, 0x99, 0xa0, 0xa4, 0xa2, 0x9f, 0x9c, 0x9b, 0x9b, 0x9d, 0x9e, + 0x9b, 0x96, 0x90, 0x89, 0x84, 0x83, 0x83, 0x85, 0x85, 0x85, 0x83, + 0x81, 0x7f, 0x7e, 0x7e, 0x7f, 0x7f, 0x7c, 0x79, 0x75, 0x72, 0x72, + 0x74, 0x76, 0x7a, 0x7c, 0x7c, 0x7b, 0x7a, 0x7a, 0x7a, 0x7c, 0x7e, + 0x7f, 0x7f, 0x7f, 0x7d, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7d, 0x7c, + 0x7a, 0x79, 0x78, 0x78, 0x79, 0x79, 0x79, 0x78, 0x78, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x78, 0x78, 0x78, 0x79, 0x79, 0x79, 0x78, + 0x78, 0x78, 0x78, 0x79, 0x79, 0x7a, 0x7a, 0x79, 0x79, 0x79, 0x7a, + 0x7a, 0x79, 0x79, 0x79, 0x79, 0x79, 0x7a, 0x7b, 0x7c, 0x7c, 0x7c, + 0x7c, 0x7e, 0x7f, 0x80, 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, 0x81, + 0x82, 0x84, 0x85, 0x87, 0x89, 0x8a, 0x8b, 0x8d, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8d, 0x8c, 0x8b, 0x8a, 0x89, + 0x88, 0x87, 0x86, 0x86, 0x85, 0x84, 0x83, 0x82, 0x81, 0x80, 0x80, + 0x7f, 0x7e, 0x7e, 0x7e, 0x7d, 0x7c, 0x7b, 0x7a, 0x7a, 0x79, 0x79, + 0x78, 0x78, 0x77, 0x77, 0x77, 0x77, 0x78, 0x79, 0x7a, 0x7a, 0x7a, + 0x7a, 0x7a, 0x7a, 0x79, 0x79, 0x78, 0x78, 0x77, 0x77, 0x77, 0x78, + 0x78, 0x78, 0x78, 0x77, 0x77, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7b, + 0x7b, 0x7c, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7e, 0x7f, + 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x81, 0x81, 0x81, 0x81, 0x80, + 0x80, 0x81, 0x80, 0x7f, 0x80, 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x81, 0x81, 0x81, 0x82, 0x82, 0x83, 0x83, 0x84, 0x84, 0x84, + 0x84, 0x83, 0x83, 0x83, 0x84, 0x85, 0x85, 0x86, 0x86, 0x85, 0x84, + 0x84, 0x84, 0x83, 0x83, 0x83, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x80, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, + 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, + 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, + 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x80, + 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x7f, + 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, + }, + { // 3 + 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x80, + 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, + 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, + 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x80, + 0x80, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, + 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, + 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, + 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x7f, + 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, + 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7f, + 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, + 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x80, + 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x80, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x7f, + 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x7f, 0x7e, 0x7f, 0x7f, 0x80, 0x81, 0x7f, 0x7f, 0x80, 0x7f, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7e, 0x7f, 0x80, + 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x7e, 0x7e, 0x7f, 0x80, 0x80, + 0x80, 0x81, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x81, 0x80, 0x7e, 0x80, + 0x7f, 0x80, 0x80, 0x7e, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, + 0x81, 0x80, 0x7d, 0x7e, 0x80, 0x7e, 0x80, 0x81, 0x7f, 0x80, 0x7f, + 0x7d, 0x81, 0x83, 0x7f, 0x7e, 0x80, 0x7f, 0x7e, 0x81, 0x7e, 0x7e, + 0x80, 0x7f, 0x81, 0x80, 0x7f, 0x7f, 0x7e, 0x82, 0x81, 0x7e, 0x80, + 0x7f, 0x7f, 0x80, 0x7f, 0x7e, 0x7f, 0x7f, 0x7f, 0x81, 0x80, 0x80, + 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x81, 0x7e, 0x7e, 0x80, + 0x80, 0x82, 0x81, 0x7e, 0x80, 0x81, 0x80, 0x80, 0x7e, 0x7d, 0x7f, + 0x7e, 0x7d, 0x7e, 0x80, 0x80, 0x80, 0x80, 0x80, 0x82, 0x7f, 0x80, + 0x80, 0x7e, 0x80, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, + 0x7f, 0x7f, 0x80, 0x7e, 0x80, 0x80, 0x7f, 0x7e, 0x7f, 0x81, 0x7f, + 0x81, 0x80, 0x80, 0x81, 0x7e, 0x80, 0x7d, 0x7e, 0x7f, 0x7b, 0x7f, + 0x7e, 0x7f, 0x80, 0x7f, 0x82, 0x7e, 0x7e, 0x82, 0x7f, 0x81, 0x83, + 0x81, 0x82, 0x84, 0x85, 0x80, 0x80, 0x7e, 0x7b, 0x7d, 0x7d, 0x7e, + 0x80, 0x83, 0x81, 0x7e, 0x81, 0x81, 0x7e, 0x7f, 0x81, 0x7e, 0x80, + 0x82, 0x7e, 0x7f, 0x80, 0x7c, 0x7d, 0x7e, 0x7f, 0x7d, 0x84, 0x89, + 0x7f, 0x7e, 0x82, 0x80, 0x81, 0x80, 0x84, 0x82, 0x7e, 0x7d, 0x75, + 0x78, 0x80, 0x7b, 0x7c, 0x82, 0x83, 0x7e, 0x7d, 0x83, 0x81, 0x83, + 0x86, 0x85, 0x84, 0x83, 0x85, 0x86, 0x84, 0x84, 0x88, 0x8b, 0x8a, + 0x89, 0x88, 0x84, 0x83, 0x84, 0x84, 0x80, 0x80, 0x82, 0x87, 0x86, + 0x82, 0x87, 0x84, 0x7e, 0x78, 0x74, 0x70, 0x69, 0x67, 0x6c, 0x70, + 0x70, 0x6f, 0x6e, 0x71, 0x73, 0x6e, 0x6f, 0x71, 0x6d, 0x6f, 0x71, + 0x6f, 0x6a, 0x6d, 0x77, 0x82, 0x8a, 0x90, 0x97, 0x98, 0x99, 0x9c, + 0x9c, 0x9a, 0x97, 0x97, 0x97, 0x94, 0x93, 0x92, 0x90, 0x91, 0x8f, + 0x90, 0x8f, 0x8b, 0x88, 0x85, 0x83, 0x80, 0x7e, 0x79, 0x76, 0x74, + 0x70, 0x6d, 0x6b, 0x69, 0x66, 0x63, 0x65, 0x66, 0x66, 0x62, 0x5e, + 0x5d, 0x5c, 0x59, 0x57, 0x5b, 0x66, 0x77, 0x89, 0x92, 0x92, 0x93, + 0x99, 0xa0, 0xa3, 0x9f, 0x99, 0x95, 0x93, 0x91, 0x8c, 0x85, 0x80, + 0x7f, 0x7f, 0x7f, 0x7f, 0x82, 0x86, 0x89, 0x8a, 0x8d, 0x91, 0x97, + 0x9b, 0x9b, 0x97, 0x90, 0x8a, 0x88, 0x87, 0x81, 0x7b, 0x77, 0x76, + 0x75, 0x74, 0x75, 0x74, 0x71, 0x6c, 0x69, 0x6a, 0x6c, 0x68, 0x62, + 0x5d, 0x5a, 0x5a, 0x58, 0x56, 0x5b, 0x69, 0x7b, 0x8b, 0x93, 0x92, + 0x91, 0x94, 0x9b, 0xa1, 0xa0, 0x9d, 0x99, 0x94, 0x8f, 0x88, 0x82, + 0x80, 0x80, 0x81, 0x7e, 0x7d, 0x7f, 0x84, 0x88, 0x8d, 0x90, 0x93, + 0x96, 0x97, 0x95, 0x91, 0x8e, 0x8b, 0x87, 0x82, 0x7d, 0x79, 0x75, + 0x73, 0x72, 0x6f, 0x6c, 0x6a, 0x69, 0x6a, 0x6b, 0x6b, 0x69, 0x66, + 0x63, 0x61, 0x5e, 0x59, 0x55, 0x56, 0x62, 0x76, 0x8b, 0x99, 0x9a, + 0x93, 0x8c, 0x8d, 0x98, 0xa5, 0xaa, 0xa6, 0x9a, 0x8d, 0x84, 0x80, + 0x80, 0x82, 0x84, 0x82, 0x7e, 0x7b, 0x7a, 0x7d, 0x82, 0x89, 0x91, + 0x97, 0x9b, 0x9b, 0x96, 0x91, 0x8d, 0x8b, 0x89, 0x85, 0x7e, 0x76, + 0x70, 0x70, 0x72, 0x72, 0x6f, 0x6c, 0x6a, 0x69, 0x68, 0x65, 0x61, + 0x5f, 0x5d, 0x5b, 0x59, 0x55, 0x53, 0x55, 0x60, 0x75, 0x8c, 0x9c, + 0x9f, 0x98, 0x8e, 0x8d, 0x98, 0xa5, 0xac, 0xa8, 0x9b, 0x8b, 0x7f, + 0x7c, 0x7f, 0x83, 0x84, 0x81, 0x7a, 0x74, 0x74, 0x7a, 0x85, 0x8f, + 0x96, 0x9a, 0x9c, 0x9b, 0x98, 0x95, 0x91, 0x8e, 0x8a, 0x84, 0x7c, + 0x75, 0x70, 0x70, 0x70, 0x6f, 0x6b, 0x67, 0x63, 0x62, 0x62, 0x60, + 0x5d, 0x5c, 0x5b, 0x59, 0x56, 0x51, 0x50, 0x56, 0x64, 0x7a, 0x90, + 0x9e, 0x9f, 0x98, 0x90, 0x90, 0x9a, 0xa6, 0xac, 0xa7, 0x98, 0x87, + 0x7b, 0x78, 0x7b, 0x80, 0x83, 0x7f, 0x79, 0x75, 0x76, 0x7f, 0x8a, + 0x94, 0x9b, 0x9e, 0x9e, 0x9d, 0x9d, 0x9b, 0x97, 0x91, 0x88, 0x7f, + 0x76, 0x70, 0x6c, 0x69, 0x66, 0x63, 0x61, 0x5f, 0x5d, 0x5b, 0x59, + 0x57, 0x56, 0x56, 0x56, 0x56, 0x54, 0x51, 0x50, 0x57, 0x69, 0x85, + 0x9e, 0xa9, 0xa3, 0x94, 0x8a, 0x8d, 0x9c, 0xaa, 0xad, 0xa2, 0x8d, + 0x7a, 0x71, 0x74, 0x7d, 0x83, 0x83, 0x7d, 0x77, 0x77, 0x7d, 0x89, + 0x96, 0xa1, 0xa8, 0xa8, 0xa4, 0x9e, 0x9a, 0x97, 0x94, 0x8e, 0x83, + 0x76, 0x6c, 0x66, 0x64, 0x64, 0x63, 0x5f, 0x59, 0x54, 0x52, 0x56, + 0x5b, 0x5a, 0x55, 0x52, 0x53, 0x56, 0x59, 0x54, 0x4e, 0x4e, 0x5b, + 0x76, 0x94, 0xa8, 0xa8, 0x9b, 0x8e, 0x8d, 0x98, 0xa6, 0xac, 0xa5, + 0x93, 0x80, 0x74, 0x73, 0x79, 0x7f, 0x80, 0x7d, 0x79, 0x78, 0x7d, + 0x87, 0x93, 0x9e, 0xa5, 0xa7, 0xa4, 0x9e, 0x98, 0x92, 0x8e, 0x89, + 0x81, 0x77, 0x6e, 0x67, 0x65, 0x64, 0x62, 0x5e, 0x5a, 0x58, 0x59, + 0x5c, 0x5e, 0x5f, 0x5e, 0x5c, 0x5a, 0x59, 0x58, 0x55, 0x4f, 0x4b, + 0x4f, 0x61, 0x7f, 0x9b, 0xa7, 0x9f, 0x91, 0x8c, 0x99, 0xad, 0xb3, + 0xa6, 0x8d, 0x7c, 0x7b, 0x85, 0x8a, 0x83, 0x75, 0x6a, 0x6c, 0x79, + 0x87, 0x8e, 0x8c, 0x89, 0x8d, 0x9b, 0xab, 0xb3, 0xae, 0x9e, 0x8f, + 0x86, 0x85, 0x83, 0x7d, 0x73, 0x69, 0x62, 0x5f, 0x60, 0x62, 0x64, + 0x62, 0x5d, 0x5b, 0x5b, 0x5a, 0x5c, 0x5f, 0x63, 0x63, 0x61, 0x5c, + 0x57, 0x54, 0x50, 0x4c, 0x4c, 0x57, 0x70, 0x8f, 0xa3, 0xa3, 0x96, + 0x8d, 0x93, 0xa6, 0xb3, 0xab, 0x95, 0x81, 0x7c, 0x83, 0x88, 0x83, + 0x77, 0x6d, 0x6e, 0x78, 0x84, 0x8a, 0x8b, 0x8b, 0x90, 0x9a, 0xa6, + 0xab, 0xa7, 0x9d, 0x94, 0x8e, 0x89, 0x82, 0x79, 0x72, 0x6f, 0x6c, + 0x68, 0x61, 0x5d, 0x5e, 0x61, 0x62, 0x5f, 0x5c, 0x5f, 0x66, 0x6a, + 0x64, 0x5c, 0x5a, 0x5f, 0x64, 0x62, 0x5b, 0x55, 0x53, 0x51, 0x50, + 0x55, 0x69, 0x87, 0x9c, 0x9a, 0x8a, 0x87, 0x9b, 0xb5, 0xb9, 0xa3, + 0x89, 0x81, 0x90, 0x9c, 0x92, 0x78, 0x66, 0x6c, 0x7e, 0x85, 0x7c, + 0x73, 0x7a, 0x8d, 0x9a, 0x9a, 0x96, 0x9a, 0xa4, 0xa7, 0x9d, 0x8f, + 0x88, 0x87, 0x85, 0x7d, 0x73, 0x6d, 0x6d, 0x6d, 0x6b, 0x68, 0x67, + 0x69, 0x6a, 0x68, 0x65, 0x62, 0x62, 0x63, 0x68, 0x6b, 0x67, 0x62, + 0x61, 0x61, 0x5d, 0x58, 0x57, 0x5d, 0x66, 0x68, 0x65, 0x69, 0x7c, + 0x97, 0xa3, 0x9c, 0x94, 0x98, 0xa3, 0xa5, 0x99, 0x8b, 0x85, 0x84, + 0x80, 0x7b, 0x79, 0x77, 0x74, 0x76, 0x7c, 0x84, 0x8b, 0x8c, 0x8d, + 0x91, 0x96, 0x99, 0x97, 0x93, 0x8e, 0x8c, 0x8c, 0x87, 0x7e, 0x78, + 0x7c, 0x83, 0x82, 0x7b, 0x77, 0x7d, 0x81, 0x7b, 0x72, 0x6e, 0x6d, + 0x66, 0x5c, 0x5c, 0x62, 0x6a, 0x71, 0x77, 0x77, 0x79, 0x80, 0x80, + 0x77, 0x6f, 0x6e, 0x6a, 0x60, 0x59, 0x59, 0x5a, 0x52, 0x47, 0x45, + 0x4b, 0x5e, 0x79, 0x89, 0x88, 0x8c, 0xa3, 0xb7, 0xb1, 0x9c, 0x9b, + 0xab, 0xa9, 0x8e, 0x7b, 0x83, 0x88, 0x79, 0x69, 0x6f, 0x7f, 0x80, + 0x79, 0x7d, 0x8d, 0x94, 0x90, 0x8e, 0x92, 0x94, 0x8f, 0x87, 0x84, + 0x86, 0x86, 0x7f, 0x78, 0x7a, 0x7f, 0x82, 0x83, 0x87, 0x8e, 0x90, + 0x8e, 0x8e, 0x8d, 0x87, 0x81, 0x7b, 0x73, 0x6c, 0x65, 0x5e, 0x5a, + 0x59, 0x59, 0x57, 0x5b, 0x65, 0x6e, 0x76, 0x7a, 0x79, 0x74, 0x6d, + 0x65, 0x5d, 0x59, 0x59, 0x58, 0x56, 0x57, 0x5b, 0x5a, 0x58, 0x5a, + 0x56, 0x54, 0x74, 0x95, 0x88, 0x7e, 0x9e, 0xbe, 0xa6, 0x8b, 0xa6, + 0xbc, 0xa0, 0x82, 0x93, 0xa1, 0x85, 0x6f, 0x7a, 0x85, 0x79, 0x72, + 0x7c, 0x85, 0x86, 0x84, 0x88, 0x8d, 0x91, 0x92, 0x8a, 0x87, 0x88, + 0x84, 0x79, 0x75, 0x7a, 0x77, 0x6f, 0x72, 0x7d, 0x82, 0x82, 0x8a, + 0x96, 0x9b, 0x98, 0x97, 0x9b, 0x97, 0x8c, 0x86, 0x83, 0x7d, 0x74, + 0x6f, 0x6e, 0x6b, 0x66, 0x63, 0x64, 0x62, 0x60, 0x61, 0x65, 0x63, + 0x61, 0x63, 0x66, 0x69, 0x68, 0x63, 0x63, 0x65, 0x62, 0x61, 0x65, + 0x66, 0x62, 0x62, 0x64, 0x66, 0x64, 0x60, 0x52, 0x67, 0x9a, 0x84, + 0x70, 0xa0, 0xba, 0x9d, 0x91, 0xb8, 0xb9, 0x96, 0x94, 0xa5, 0x9d, + 0x82, 0x80, 0x85, 0x7d, 0x74, 0x73, 0x7b, 0x78, 0x76, 0x7b, 0x80, + 0x84, 0x84, 0x8a, 0x8d, 0x8c, 0x8a, 0x87, 0x86, 0x7f, 0x79, 0x76, + 0x73, 0x71, 0x71, 0x74, 0x77, 0x7b, 0x7f, 0x83, 0x86, 0x88, 0x8b, + 0x8d, 0x8f, 0x90, 0x8e, 0x8d, 0x8d, 0x8a, 0x84, 0x82, 0x82, 0x7d, + 0x7a, 0x7d, 0x7c, 0x77, 0x78, 0x7a, 0x78, 0x76, 0x75, 0x74, 0x75, + 0x71, 0x6c, 0x6d, 0x6e, 0x6b, 0x68, 0x6b, 0x6c, 0x6a, 0x6d, 0x6d, + 0x69, 0x6c, 0x6f, 0x6a, 0x6b, 0x6f, 0x6c, 0x65, 0x66, 0x5f, 0x5f, + 0x83, 0x7c, 0x6f, 0x93, 0xa0, 0x94, 0x96, 0xac, 0xaa, 0x9d, 0xa0, + 0xa1, 0x9c, 0x8c, 0x84, 0x88, 0x7e, 0x71, 0x74, 0x79, 0x73, 0x70, + 0x7b, 0x81, 0x7e, 0x85, 0x8c, 0x8a, 0x8b, 0x8d, 0x8e, 0x89, 0x82, + 0x85, 0x82, 0x7a, 0x76, 0x77, 0x77, 0x73, 0x72, 0x76, 0x7b, 0x7a, + 0x7d, 0x87, 0x85, 0x85, 0x8b, 0x89, 0x87, 0x87, 0x87, 0x85, 0x85, + 0x85, 0x85, 0x87, 0x83, 0x81, 0x82, 0x7f, 0x7d, 0x7e, 0x7f, 0x7b, + 0x78, 0x79, 0x79, 0x75, 0x75, 0x75, 0x75, 0x75, 0x72, 0x72, 0x73, + 0x70, 0x6e, 0x6f, 0x6e, 0x6c, 0x6c, 0x6b, 0x6a, 0x6c, 0x6d, 0x6e, + 0x6c, 0x6b, 0x68, 0x66, 0x63, 0x5e, 0x7e, 0x7a, 0x6a, 0x8f, 0x9a, + 0x8c, 0x95, 0xa9, 0xa0, 0x9a, 0xa2, 0xa1, 0x9b, 0x92, 0x92, 0x91, + 0x85, 0x7c, 0x80, 0x7f, 0x73, 0x76, 0x7c, 0x7a, 0x79, 0x81, 0x85, + 0x81, 0x86, 0x8b, 0x8b, 0x89, 0x88, 0x89, 0x86, 0x7f, 0x80, 0x7f, + 0x77, 0x79, 0x79, 0x77, 0x77, 0x78, 0x7a, 0x7c, 0x7e, 0x80, 0x82, + 0x83, 0x85, 0x86, 0x87, 0x88, 0x87, 0x88, 0x87, 0x84, 0x84, 0x84, + 0x80, 0x7d, 0x7f, 0x7a, 0x76, 0x78, 0x76, 0x74, 0x74, 0x75, 0x75, + 0x74, 0x76, 0x75, 0x77, 0x77, 0x78, 0x7a, 0x77, 0x78, 0x7a, 0x77, + 0x76, 0x75, 0x74, 0x72, 0x71, 0x74, 0x72, 0x74, 0x73, 0x71, 0x71, + 0x6d, 0x6c, 0x68, 0x71, 0x7a, 0x71, 0x7d, 0x8a, 0x87, 0x89, 0x96, + 0x98, 0x95, 0x9b, 0x9f, 0x9c, 0x98, 0x99, 0x98, 0x90, 0x8c, 0x8d, + 0x88, 0x80, 0x81, 0x82, 0x7b, 0x7b, 0x7f, 0x7e, 0x7d, 0x7f, 0x83, + 0x81, 0x81, 0x84, 0x83, 0x83, 0x82, 0x82, 0x81, 0x7f, 0x7e, 0x7e, + 0x7c, 0x7a, 0x7c, 0x7b, 0x7a, 0x7c, 0x7d, 0x7d, 0x7e, 0x81, 0x82, + 0x82, 0x84, 0x85, 0x84, 0x84, 0x83, 0x82, 0x80, 0x7e, 0x7d, 0x7b, + 0x79, 0x79, 0x76, 0x75, 0x75, 0x74, 0x73, 0x73, 0x75, 0x74, 0x74, + 0x77, 0x77, 0x75, 0x77, 0x77, 0x76, 0x76, 0x76, 0x75, 0x74, 0x72, + 0x78, 0x77, 0x77, 0x7d, 0x7e, 0x7d, 0x79, 0x78, 0x75, 0x71, 0x6f, + 0x71, 0x7c, 0x75, 0x78, 0x87, 0x83, 0x84, 0x8d, 0x90, 0x8e, 0x93, + 0x96, 0x95, 0x95, 0x95, 0x95, 0x91, 0x90, 0x8f, 0x8b, 0x88, 0x87, + 0x86, 0x83, 0x82, 0x83, 0x82, 0x81, 0x82, 0x81, 0x80, 0x80, 0x81, + 0x80, 0x7f, 0x7f, 0x7f, 0x7c, 0x7c, 0x7c, 0x7a, 0x7a, 0x7a, 0x7a, + 0x7a, 0x7a, 0x7b, 0x7c, 0x7c, 0x7e, 0x7f, 0x7f, 0x7f, 0x80, 0x80, + 0x80, 0x80, 0x81, 0x80, 0x7f, 0x80, 0x7f, 0x7e, 0x7e, 0x7e, 0x7d, + 0x7d, 0x7c, 0x7c, 0x7c, 0x7b, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, + 0x7d, 0x7c, 0x7d, 0x7d, 0x7d, 0x7c, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, + 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7c, 0x7d, 0x7d, 0x7d, 0x7d, 0x7e, + 0x7e, 0x7d, 0x7e, 0x7e, 0x7d, 0x7e, 0x7d, 0x7d, 0x7d, 0x7c, 0x7c, + 0x7c, 0x7c, 0x7c, 0x7c, 0x7d, 0x7d, 0x7e, 0x7f, 0x80, 0x80, 0x80, + 0x82, 0x82, 0x82, 0x83, 0x84, 0x84, 0x84, 0x86, 0x85, 0x86, 0x87, + 0x87, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x87, 0x87, 0x86, + 0x84, 0x84, 0x82, 0x80, 0x7f, 0x7d, 0x7c, 0x7a, 0x79, 0x79, 0x78, + 0x77, 0x77, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x77, 0x77, 0x78, + 0x78, 0x79, 0x7a, 0x79, 0x7b, 0x7b, 0x7a, 0x7c, 0x7b, 0x7b, 0x7d, + 0x7c, 0x7c, 0x7d, 0x7c, 0x7c, 0x7e, 0x7d, 0x7c, 0x7e, 0x7e, 0x7c, + 0x7d, 0x7d, 0x7c, 0x7c, 0x7d, 0x7d, 0x7c, 0x7d, 0x7d, 0x7c, 0x7d, + 0x7e, 0x7d, 0x7e, 0x7f, 0x7e, 0x7e, 0x7f, 0x7f, 0x7e, 0x7f, 0x7f, + 0x7f, 0x7f, 0x81, 0x82, 0x83, 0x85, 0x86, 0x86, 0x88, 0x89, 0x8a, + 0x8b, 0x8c, 0x8c, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8b, 0x8b, 0x8a, + 0x89, 0x88, 0x87, 0x86, 0x85, 0x85, 0x83, 0x82, 0x81, 0x80, 0x7e, + 0x7d, 0x7c, 0x7b, 0x79, 0x79, 0x78, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x78, 0x78, 0x78, 0x79, 0x79, 0x7a, 0x7a, 0x7a, + 0x7a, 0x7a, 0x7b, 0x7b, 0x7b, 0x7c, 0x7d, 0x7c, 0x7e, 0x7f, 0x7e, + 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, 0x7d, 0x7c, 0x7c, + 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7c, 0x7c, 0x7d, 0x7d, 0x7e, 0x7f, + 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x7f, + 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x81, 0x81, 0x82, 0x82, + 0x83, 0x83, 0x83, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x83, 0x83, 0x83, 0x82, 0x82, 0x81, 0x81, + 0x81, 0x80, 0x80, 0x80, 0x7f, 0x7e, 0x7e, 0x7d, 0x7d, 0x7d, 0x7d, + 0x7d, 0x7d, 0x7d, 0x7c, 0x7c, 0x7c, 0x7d, 0x7d, 0x7d, 0x7d, 0x7e, + 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, + 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, + 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, + 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x7e, 0x7f, 0x7f, 0x7f, + 0x80, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, + 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, + 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x80, + 0x7f, 0x80, 0x80, + }, + { // 4 + 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, + 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, + 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x7f, + 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, + 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, + 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x80, + 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, + 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x7f, + 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x81, 0x80, 0x7f, + 0x80, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x82, 0x80, 0x7f, + 0x7f, 0x7e, 0x7e, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7e, 0x80, 0x80, + 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x81, 0x80, 0x7f, 0x7f, 0x80, 0x80, + 0x80, 0x7e, 0x7e, 0x7e, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, + 0x7e, 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x81, 0x80, 0x7f, 0x7f, 0x80, + 0x81, 0x80, 0x7f, 0x80, 0x81, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x80, + 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, + 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7e, 0x7f, 0x7f, 0x7f, + 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x7e, 0x7f, 0x80, 0x80, 0x80, 0x81, 0x82, 0x7f, 0x7e, + 0x80, 0x80, 0x80, 0x7f, 0x7d, 0x7f, 0x7f, 0x80, 0x81, 0x80, 0x80, + 0x7f, 0x80, 0x81, 0x7e, 0x80, 0x80, 0x7f, 0x7e, 0x7e, 0x7e, 0x81, + 0x7e, 0x80, 0x81, 0x7d, 0x80, 0x7f, 0x80, 0x81, 0x7e, 0x80, 0x81, + 0x81, 0x82, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x7e, 0x80, 0x80, 0x7f, + 0x80, 0x7f, 0x7e, 0x7e, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x81, 0x7d, 0x7c, 0x7e, 0x82, 0x82, 0x80, 0x7f, 0x7e, 0x80, + 0x80, 0x7f, 0x7f, 0x7f, 0x80, 0x82, 0x81, 0x7f, 0x7e, 0x80, 0x7f, + 0x80, 0x81, 0x7f, 0x7e, 0x7f, 0x81, 0x80, 0x7d, 0x7e, 0x80, 0x80, + 0x82, 0x80, 0x7c, 0x80, 0x81, 0x7f, 0x7f, 0x7f, 0x7e, 0x80, 0x80, + 0x80, 0x7e, 0x7e, 0x80, 0x7f, 0x80, 0x7e, 0x7e, 0x80, 0x82, 0x81, + 0x7f, 0x81, 0x82, 0x7f, 0x7f, 0x82, 0x7f, 0x7e, 0x7f, 0x7e, 0x7e, + 0x80, 0x83, 0x81, 0x80, 0x7f, 0x7d, 0x80, 0x81, 0x7f, 0x80, 0x80, + 0x7e, 0x7e, 0x7e, 0x80, 0x81, 0x7f, 0x7e, 0x7e, 0x7f, 0x83, 0x82, + 0x81, 0x80, 0x7f, 0x80, 0x7e, 0x7d, 0x80, 0x82, 0x81, 0x7d, 0x7e, + 0x7e, 0x7d, 0x7d, 0x80, 0x82, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7e, + 0x80, 0x83, 0x81, 0x80, 0x80, 0x80, 0x81, 0x7f, 0x80, 0x80, 0x7e, + 0x7e, 0x7f, 0x7f, 0x7e, 0x7e, 0x80, 0x83, 0x81, 0x7e, 0x80, 0x81, + 0x81, 0x80, 0x7f, 0x7e, 0x7e, 0x7f, 0x80, 0x7e, 0x7e, 0x82, 0x80, + 0x7d, 0x7f, 0x83, 0x81, 0x7f, 0x7c, 0x7e, 0x83, 0x80, 0x80, 0x80, + 0x81, 0x80, 0x7b, 0x7a, 0x7f, 0x82, 0x83, 0x82, 0x7d, 0x7e, 0x7f, + 0x7f, 0x80, 0x7e, 0x7f, 0x81, 0x81, 0x80, 0x7f, 0x7d, 0x7d, 0x7d, + 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x81, 0x80, 0x7f, 0x7f, 0x7e, 0x7d, + 0x7f, 0x7e, 0x7e, 0x7d, 0x7b, 0x7b, 0x7c, 0x80, 0x81, 0x81, 0x82, + 0x83, 0x86, 0x88, 0x8a, 0x8d, 0x8e, 0x8c, 0x8b, 0x8a, 0x87, 0x86, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x82, 0x7f, 0x7d, 0x7d, 0x7d, 0x7f, + 0x83, 0x82, 0x7d, 0x79, 0x76, 0x72, 0x6f, 0x6c, 0x6a, 0x6b, 0x6c, + 0x6c, 0x6c, 0x6a, 0x65, 0x62, 0x63, 0x62, 0x60, 0x5e, 0x5e, 0x63, + 0x6b, 0x7a, 0x8e, 0xa1, 0xac, 0xad, 0xae, 0xa9, 0xa0, 0x97, 0x8d, + 0x87, 0x84, 0x82, 0x83, 0x83, 0x83, 0x81, 0x7f, 0x7d, 0x7b, 0x7d, + 0x80, 0x83, 0x89, 0x8c, 0x90, 0x92, 0x93, 0x91, 0x8c, 0x89, 0x86, + 0x84, 0x84, 0x84, 0x83, 0x80, 0x7e, 0x7a, 0x76, 0x74, 0x71, 0x70, + 0x6f, 0x6d, 0x6a, 0x66, 0x63, 0x5f, 0x5c, 0x5a, 0x58, 0x57, 0x55, + 0x55, 0x5e, 0x6c, 0x80, 0x98, 0xad, 0xb8, 0xb9, 0xb4, 0xa9, 0x99, + 0x8a, 0x7d, 0x75, 0x74, 0x75, 0x79, 0x7e, 0x80, 0x81, 0x80, 0x7f, + 0x80, 0x83, 0x88, 0x8f, 0x96, 0x9a, 0x9b, 0x97, 0x8f, 0x86, 0x7d, + 0x76, 0x74, 0x76, 0x7b, 0x80, 0x85, 0x87, 0x85, 0x83, 0x80, 0x7d, + 0x7c, 0x7b, 0x7a, 0x78, 0x74, 0x6f, 0x69, 0x64, 0x60, 0x5d, 0x5b, + 0x5c, 0x5d, 0x5f, 0x62, 0x67, 0x71, 0x7e, 0x8f, 0xa0, 0xae, 0xb8, + 0xb9, 0xb2, 0xa5, 0x95, 0x86, 0x79, 0x72, 0x6f, 0x71, 0x75, 0x7a, + 0x7d, 0x80, 0x81, 0x81, 0x83, 0x86, 0x8b, 0x91, 0x98, 0x9c, 0x9c, + 0x99, 0x91, 0x86, 0x7c, 0x73, 0x6f, 0x6f, 0x73, 0x78, 0x7e, 0x83, + 0x85, 0x85, 0x83, 0x80, 0x7e, 0x7d, 0x7e, 0x7d, 0x7c, 0x79, 0x74, + 0x6e, 0x67, 0x61, 0x5d, 0x5b, 0x5b, 0x5c, 0x5f, 0x62, 0x66, 0x6e, + 0x79, 0x87, 0x98, 0xa6, 0xb2, 0xb7, 0xb5, 0xad, 0xa0, 0x91, 0x81, + 0x76, 0x6e, 0x6a, 0x6c, 0x70, 0x74, 0x79, 0x7d, 0x81, 0x84, 0x88, + 0x8c, 0x90, 0x95, 0x98, 0x99, 0x98, 0x93, 0x8b, 0x81, 0x78, 0x71, + 0x6d, 0x70, 0x75, 0x7c, 0x84, 0x89, 0x8b, 0x8a, 0x88, 0x85, 0x81, + 0x7e, 0x7c, 0x7a, 0x79, 0x77, 0x75, 0x70, 0x6b, 0x66, 0x61, 0x5e, + 0x5d, 0x5c, 0x5e, 0x60, 0x63, 0x68, 0x71, 0x7d, 0x8c, 0x9a, 0xa8, + 0xb1, 0xb3, 0xb0, 0xa7, 0x9a, 0x8c, 0x7f, 0x75, 0x6f, 0x6e, 0x70, + 0x74, 0x79, 0x7e, 0x82, 0x86, 0x88, 0x8c, 0x8f, 0x92, 0x95, 0x95, + 0x93, 0x8e, 0x87, 0x7f, 0x77, 0x73, 0x71, 0x73, 0x79, 0x7f, 0x85, + 0x8a, 0x8c, 0x8b, 0x88, 0x84, 0x80, 0x7c, 0x79, 0x77, 0x75, 0x74, + 0x73, 0x71, 0x6e, 0x6b, 0x69, 0x67, 0x67, 0x67, 0x65, 0x65, 0x64, + 0x63, 0x63, 0x69, 0x72, 0x7e, 0x90, 0xa0, 0xae, 0xb9, 0xba, 0xb5, + 0xaa, 0x9b, 0x8b, 0x7d, 0x74, 0x6e, 0x6c, 0x6e, 0x70, 0x74, 0x78, + 0x7a, 0x7e, 0x82, 0x87, 0x8c, 0x92, 0x98, 0x9a, 0x9a, 0x96, 0x8d, + 0x84, 0x78, 0x6f, 0x69, 0x67, 0x6b, 0x74, 0x7f, 0x8a, 0x93, 0x98, + 0x96, 0x91, 0x8a, 0x82, 0x7c, 0x77, 0x74, 0x74, 0x74, 0x74, 0x74, + 0x73, 0x72, 0x70, 0x6e, 0x6c, 0x6b, 0x6a, 0x69, 0x68, 0x66, 0x65, + 0x64, 0x63, 0x67, 0x6e, 0x7b, 0x8b, 0x9b, 0xab, 0xb6, 0xba, 0xb7, + 0xad, 0x9f, 0x90, 0x82, 0x77, 0x70, 0x6d, 0x6d, 0x6f, 0x72, 0x76, + 0x79, 0x7d, 0x81, 0x86, 0x8b, 0x91, 0x96, 0x99, 0x9a, 0x95, 0x8e, + 0x84, 0x78, 0x6d, 0x65, 0x62, 0x63, 0x6a, 0x76, 0x82, 0x8e, 0x98, + 0x9d, 0x9e, 0x9a, 0x93, 0x8b, 0x82, 0x7a, 0x73, 0x6f, 0x6b, 0x6a, + 0x6a, 0x6b, 0x6e, 0x72, 0x77, 0x7c, 0x7f, 0x80, 0x7f, 0x7b, 0x75, + 0x6d, 0x65, 0x5e, 0x58, 0x57, 0x5a, 0x63, 0x72, 0x84, 0x99, 0xab, + 0xb8, 0xbd, 0xbb, 0xb3, 0xa6, 0x96, 0x87, 0x79, 0x70, 0x6a, 0x68, + 0x69, 0x6c, 0x71, 0x76, 0x7c, 0x82, 0x88, 0x8e, 0x93, 0x98, 0x9b, + 0x9a, 0x96, 0x8f, 0x84, 0x78, 0x6d, 0x64, 0x60, 0x60, 0x65, 0x6f, + 0x7b, 0x88, 0x93, 0x9b, 0x9f, 0x9f, 0x9a, 0x94, 0x8c, 0x84, 0x7c, + 0x75, 0x6f, 0x6b, 0x69, 0x68, 0x6a, 0x6d, 0x71, 0x77, 0x7d, 0x81, + 0x84, 0x82, 0x7e, 0x78, 0x70, 0x69, 0x63, 0x5e, 0x5d, 0x5d, 0x60, + 0x64, 0x6b, 0x76, 0x83, 0x92, 0xa1, 0xae, 0xb7, 0xb8, 0xb4, 0xac, + 0x9f, 0x91, 0x82, 0x77, 0x70, 0x6b, 0x6c, 0x6e, 0x71, 0x76, 0x79, + 0x7e, 0x82, 0x87, 0x8c, 0x90, 0x93, 0x93, 0x91, 0x8d, 0x86, 0x7e, + 0x76, 0x70, 0x6c, 0x6b, 0x6e, 0x73, 0x79, 0x82, 0x8a, 0x90, 0x95, + 0x96, 0x94, 0x8f, 0x89, 0x82, 0x7c, 0x78, 0x75, 0x74, 0x75, 0x76, + 0x77, 0x78, 0x79, 0x79, 0x79, 0x7a, 0x7a, 0x79, 0x78, 0x76, 0x74, + 0x71, 0x6e, 0x6c, 0x6a, 0x68, 0x67, 0x67, 0x67, 0x67, 0x68, 0x68, + 0x70, 0x7d, 0x8a, 0x9d, 0xad, 0xb6, 0xba, 0xb4, 0xa7, 0x96, 0x84, + 0x76, 0x6b, 0x69, 0x6c, 0x70, 0x78, 0x7d, 0x7e, 0x7f, 0x80, 0x81, + 0x84, 0x8a, 0x90, 0x94, 0x97, 0x97, 0x8f, 0x87, 0x7c, 0x70, 0x68, + 0x63, 0x64, 0x69, 0x73, 0x7d, 0x84, 0x8a, 0x8d, 0x8b, 0x8b, 0x8a, + 0x88, 0x89, 0x88, 0x87, 0x86, 0x84, 0x80, 0x7d, 0x7c, 0x7e, 0x7f, + 0x83, 0x86, 0x86, 0x85, 0x82, 0x7e, 0x79, 0x75, 0x73, 0x72, 0x73, + 0x74, 0x75, 0x75, 0x75, 0x74, 0x72, 0x71, 0x70, 0x6e, 0x6d, 0x6c, + 0x6b, 0x6a, 0x6a, 0x69, 0x67, 0x66, 0x65, 0x6a, 0x7a, 0x8a, 0x9c, + 0xb0, 0xb8, 0xb7, 0xaf, 0xa0, 0x8c, 0x7a, 0x70, 0x6b, 0x6c, 0x74, + 0x7b, 0x7e, 0x81, 0x80, 0x7c, 0x7c, 0x81, 0x89, 0x92, 0x9c, 0xa0, + 0x9b, 0x92, 0x85, 0x75, 0x6a, 0x64, 0x63, 0x69, 0x72, 0x7c, 0x83, + 0x87, 0x89, 0x88, 0x86, 0x86, 0x87, 0x88, 0x8a, 0x89, 0x87, 0x81, + 0x7a, 0x74, 0x71, 0x72, 0x77, 0x7e, 0x87, 0x8f, 0x95, 0x97, 0x95, + 0x91, 0x8a, 0x81, 0x7a, 0x73, 0x6f, 0x6e, 0x6f, 0x73, 0x76, 0x7a, + 0x7c, 0x7d, 0x7e, 0x7c, 0x78, 0x76, 0x72, 0x70, 0x6f, 0x6e, 0x6d, + 0x6b, 0x69, 0x68, 0x67, 0x67, 0x66, 0x64, 0x65, 0x68, 0x76, 0x8a, + 0x9e, 0xaf, 0xba, 0xb9, 0xad, 0x9a, 0x86, 0x77, 0x6d, 0x6e, 0x76, + 0x7e, 0x84, 0x86, 0x83, 0x7f, 0x7c, 0x7e, 0x86, 0x90, 0x99, 0x9f, + 0x9b, 0x8e, 0x80, 0x72, 0x69, 0x66, 0x6b, 0x75, 0x7c, 0x80, 0x82, + 0x80, 0x7d, 0x7d, 0x80, 0x84, 0x88, 0x8a, 0x88, 0x84, 0x7f, 0x7b, + 0x78, 0x78, 0x7b, 0x7e, 0x80, 0x85, 0x87, 0x89, 0x8b, 0x8c, 0x8a, + 0x89, 0x86, 0x83, 0x7e, 0x7c, 0x7c, 0x7c, 0x7c, 0x7d, 0x7d, 0x7d, + 0x7b, 0x7b, 0x7b, 0x79, 0x77, 0x75, 0x73, 0x71, 0x6f, 0x70, 0x70, + 0x71, 0x72, 0x72, 0x72, 0x72, 0x71, 0x70, 0x6e, 0x6c, 0x6c, 0x70, + 0x73, 0x75, 0x7c, 0x91, 0xa7, 0xb2, 0xb1, 0xa8, 0x9a, 0x88, 0x79, + 0x78, 0x7e, 0x82, 0x82, 0x81, 0x80, 0x7e, 0x7f, 0x87, 0x91, 0x96, + 0x95, 0x8f, 0x89, 0x82, 0x7a, 0x78, 0x7a, 0x7b, 0x7b, 0x7a, 0x7b, + 0x7d, 0x7c, 0x7d, 0x80, 0x82, 0x83, 0x82, 0x81, 0x81, 0x81, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7d, 0x7c, 0x7d, 0x7d, 0x7e, 0x80, 0x85, 0x8a, + 0x8d, 0x8e, 0x8d, 0x8a, 0x85, 0x7f, 0x7c, 0x7b, 0x7b, 0x7c, 0x7c, + 0x7e, 0x7e, 0x7d, 0x7c, 0x7c, 0x7d, 0x7c, 0x7a, 0x78, 0x75, 0x72, + 0x70, 0x70, 0x71, 0x72, 0x72, 0x72, 0x73, 0x74, 0x74, 0x75, 0x74, + 0x71, 0x6f, 0x6d, 0x6b, 0x6a, 0x6a, 0x6d, 0x71, 0x78, 0x8f, 0xad, + 0xba, 0xb2, 0x9f, 0x92, 0x89, 0x80, 0x7e, 0x85, 0x89, 0x87, 0x7e, + 0x79, 0x7f, 0x88, 0x8c, 0x8d, 0x8d, 0x8d, 0x8a, 0x84, 0x81, 0x81, + 0x7f, 0x79, 0x75, 0x78, 0x7e, 0x81, 0x7f, 0x7f, 0x80, 0x80, 0x7f, + 0x7e, 0x82, 0x85, 0x82, 0x7e, 0x7c, 0x7d, 0x7f, 0x7f, 0x7e, 0x7f, + 0x7f, 0x7f, 0x7e, 0x7f, 0x83, 0x89, 0x8d, 0x8e, 0x8c, 0x89, 0x84, + 0x7f, 0x7c, 0x7b, 0x7d, 0x7e, 0x7f, 0x7e, 0x7d, 0x7b, 0x7b, 0x7c, + 0x7c, 0x7b, 0x7a, 0x79, 0x79, 0x79, 0x76, 0x73, 0x72, 0x73, 0x75, + 0x76, 0x76, 0x77, 0x77, 0x75, 0x72, 0x71, 0x71, 0x72, 0x71, 0x70, + 0x70, 0x71, 0x70, 0x6d, 0x6f, 0x80, 0x9e, 0xb5, 0xb4, 0xa0, 0x8d, + 0x8a, 0x8d, 0x8c, 0x87, 0x83, 0x81, 0x80, 0x7e, 0x7e, 0x86, 0x8e, + 0x8e, 0x88, 0x84, 0x88, 0x8e, 0x8c, 0x83, 0x7c, 0x7a, 0x7d, 0x7e, + 0x7c, 0x7d, 0x7e, 0x7e, 0x7e, 0x7d, 0x7f, 0x81, 0x80, 0x7c, 0x7a, + 0x7c, 0x82, 0x85, 0x81, 0x7c, 0x7a, 0x7c, 0x7f, 0x80, 0x7f, 0x81, + 0x84, 0x84, 0x82, 0x83, 0x87, 0x8a, 0x86, 0x7f, 0x7b, 0x7e, 0x80, + 0x7e, 0x79, 0x79, 0x7d, 0x81, 0x81, 0x7d, 0x78, 0x75, 0x74, 0x75, + 0x78, 0x7a, 0x7a, 0x77, 0x76, 0x77, 0x78, 0x78, 0x76, 0x76, 0x76, + 0x77, 0x78, 0x79, 0x79, 0x78, 0x78, 0x78, 0x77, 0x76, 0x74, 0x74, + 0x73, 0x71, 0x72, 0x7e, 0x93, 0xa4, 0xa5, 0x97, 0x89, 0x88, 0x91, + 0x95, 0x8e, 0x83, 0x7e, 0x82, 0x87, 0x88, 0x86, 0x86, 0x86, 0x86, + 0x85, 0x87, 0x8a, 0x8c, 0x87, 0x7f, 0x7b, 0x7d, 0x81, 0x82, 0x80, + 0x7d, 0x7b, 0x7c, 0x7e, 0x81, 0x82, 0x81, 0x7e, 0x7d, 0x7d, 0x7f, + 0x82, 0x84, 0x85, 0x83, 0x80, 0x7d, 0x7e, 0x81, 0x82, 0x80, 0x7d, + 0x7d, 0x81, 0x83, 0x81, 0x7d, 0x7c, 0x7c, 0x7c, 0x7a, 0x79, 0x79, + 0x7b, 0x7a, 0x79, 0x78, 0x79, 0x79, 0x78, 0x79, 0x7b, 0x7b, 0x79, + 0x77, 0x77, 0x79, 0x7a, 0x7a, 0x7a, 0x7b, 0x7d, 0x7c, 0x7b, 0x79, + 0x7a, 0x7b, 0x7b, 0x7b, 0x7a, 0x7a, 0x7a, 0x7a, 0x7b, 0x7b, 0x7b, + 0x79, 0x78, 0x7a, 0x80, 0x89, 0x8e, 0x8d, 0x87, 0x83, 0x85, 0x8a, + 0x8c, 0x8a, 0x88, 0x88, 0x8a, 0x8a, 0x8a, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x8a, 0x8c, 0x8b, 0x89, 0x86, 0x84, 0x83, 0x84, 0x85, 0x86, + 0x86, 0x84, 0x82, 0x81, 0x82, 0x83, 0x82, 0x80, 0x7f, 0x7f, 0x7f, + 0x7f, 0x80, 0x7f, 0x7e, 0x7c, 0x7c, 0x7d, 0x7f, 0x7f, 0x7f, 0x7e, + 0x7d, 0x7d, 0x7d, 0x7c, 0x7b, 0x7a, 0x79, 0x7a, 0x7b, 0x7b, 0x7a, + 0x79, 0x77, 0x78, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x78, 0x79, + 0x7a, 0x7a, 0x79, 0x78, 0x7a, 0x7d, 0x7d, 0x7a, 0x79, 0x7a, 0x7b, + 0x7c, 0x7b, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x7f, 0x7d, 0x7d, + 0x80, 0x83, 0x82, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x7f, + 0x7f, 0x80, 0x81, 0x81, 0x80, 0x81, 0x83, 0x85, 0x84, 0x84, 0x85, + 0x86, 0x85, 0x85, 0x85, 0x87, 0x88, 0x88, 0x88, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x88, 0x89, 0x89, 0x88, 0x87, 0x88, 0x89, 0x88, + 0x86, 0x86, 0x87, 0x88, 0x86, 0x84, 0x83, 0x83, 0x82, 0x81, 0x81, + 0x81, 0x81, 0x80, 0x7e, 0x7e, 0x7d, 0x7b, 0x7a, 0x7a, 0x7a, 0x7a, + 0x79, 0x79, 0x7a, 0x7a, 0x79, 0x78, 0x77, 0x79, 0x7a, 0x7a, 0x7a, + 0x79, 0x79, 0x79, 0x79, 0x7a, 0x7b, 0x7c, 0x7c, 0x7b, 0x7a, 0x7a, + 0x7c, 0x7d, 0x7b, 0x7a, 0x7b, 0x7e, 0x7f, 0x7d, 0x7b, 0x7c, 0x7d, + 0x7d, 0x7c, 0x7c, 0x7e, 0x7e, 0x7c, 0x7b, 0x7d, 0x7f, 0x7e, 0x7c, + 0x7c, 0x7d, 0x7d, 0x7c, 0x7c, 0x7d, 0x7e, 0x7e, 0x7d, 0x7d, 0x7d, + 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x82, 0x83, 0x82, 0x81, 0x81, + 0x82, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x84, 0x84, 0x84, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x84, 0x84, 0x84, 0x85, 0x84, 0x85, + 0x85, 0x85, 0x84, 0x83, 0x83, 0x83, 0x82, 0x80, 0x81, 0x82, 0x82, + 0x81, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7e, 0x7e, 0x7d, 0x7d, 0x7d, + 0x7d, 0x7d, 0x7d, 0x7d, 0x7c, 0x7c, 0x7b, 0x7c, 0x7c, 0x7c, 0x7c, + 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, + 0x7c, 0x7d, 0x7d, 0x7c, 0x7c, 0x7c, 0x7c, 0x7d, 0x7d, 0x7c, 0x7c, + 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7e, 0x7e, 0x7d, 0x7d, 0x7e, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x81, 0x80, 0x80, 0x80, + 0x82, 0x82, 0x81, 0x81, 0x81, 0x82, 0x82, 0x82, 0x82, 0x82, 0x81, + 0x82, 0x83, 0x83, 0x83, 0x82, 0x82, 0x82, 0x82, 0x83, 0x83, 0x83, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x7f, 0x7e, 0x7f, 0x7e, 0x7e, 0x7e, 0x7d, 0x7d, + 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7c, 0x7d, 0x7d, 0x7d, 0x7d, 0x7e, + 0x7d, 0x7d, 0x7d, 0x7e, 0x7e, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, + 0x7e, 0x7e, 0x7f, 0x7f, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7e, 0x7f, + 0x7f, 0x7f, 0x7e, 0x7e, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, + 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, + 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, + 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, + 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, + }, + { // 5 + 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, + 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, + 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, + 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x7f, + 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, + 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x7f, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, + 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x80, + 0x80, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, + 0x7e, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x7f, + 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x81, 0x80, + 0x80, 0x7f, 0x81, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, + 0x80, 0x7f, 0x7e, 0x7f, 0x7f, 0x7e, 0x7f, 0x7f, 0x7f, 0x80, 0x80, + 0x82, 0x82, 0x80, 0x7f, 0x7f, 0x80, 0x81, 0x80, 0x7f, 0x7f, 0x7f, + 0x80, 0x80, 0x80, 0x80, 0x81, 0x80, 0x7f, 0x7e, 0x7f, 0x80, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x81, 0x80, + 0x7f, 0x7e, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, + 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x80, 0x81, 0x80, 0x7f, + 0x7f, 0x7e, 0x7e, 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x81, 0x80, 0x81, + 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x7d, 0x7f, 0x7f, 0x7e, 0x80, + 0x80, 0x7e, 0x7f, 0x81, 0x81, 0x80, 0x81, 0x80, 0x7e, 0x7e, 0x7f, + 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x81, 0x7f, 0x80, 0x81, 0x7f, 0x7e, + 0x7f, 0x7f, 0x80, 0x84, 0x83, 0x7f, 0x7e, 0x80, 0x80, 0x80, 0x7f, + 0x81, 0x80, 0x7c, 0x7e, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x82, 0x81, + 0x80, 0x81, 0x7e, 0x7e, 0x7f, 0x80, 0x81, 0x81, 0x7f, 0x7e, 0x7e, + 0x7f, 0x80, 0x7f, 0x7f, 0x7d, 0x7e, 0x81, 0x80, 0x7d, 0x80, 0x80, + 0x81, 0x7f, 0x7d, 0x80, 0x80, 0x81, 0x7f, 0x7e, 0x80, 0x7f, 0x80, + 0x7f, 0x7e, 0x82, 0x81, 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, 0x81, 0x7f, + 0x7f, 0x81, 0x80, 0x7e, 0x7f, 0x80, 0x7f, 0x80, 0x7e, 0x81, 0x81, + 0x7d, 0x81, 0x83, 0x80, 0x80, 0x7f, 0x7e, 0x80, 0x80, 0x7f, 0x7e, + 0x7e, 0x81, 0x83, 0x80, 0x7f, 0x7e, 0x80, 0x80, 0x7e, 0x80, 0x7f, + 0x82, 0x80, 0x7d, 0x81, 0x7f, 0x7d, 0x7d, 0x86, 0x80, 0x78, 0x7e, + 0x82, 0x82, 0x7f, 0x7b, 0x80, 0x84, 0x7f, 0x7d, 0x7c, 0x80, 0x80, + 0x81, 0x80, 0x7c, 0x82, 0x81, 0x80, 0x7e, 0x7d, 0x82, 0x80, 0x7d, + 0x81, 0x81, 0x81, 0x7f, 0x7c, 0x84, 0x81, 0x7b, 0x7d, 0x84, 0x85, + 0x7b, 0x7d, 0x83, 0x81, 0x7d, 0x7e, 0x80, 0x7f, 0x81, 0x80, 0x7e, + 0x7f, 0x81, 0x80, 0x7e, 0x81, 0x7e, 0x81, 0x82, 0x7e, 0x7f, 0x7e, + 0x7f, 0x7f, 0x79, 0x7a, 0x7f, 0x81, 0x81, 0x7f, 0x81, 0x80, 0x7a, + 0x7e, 0x81, 0x80, 0x80, 0x80, 0x82, 0x80, 0x80, 0x7e, 0x7d, 0x80, + 0x80, 0x7e, 0x81, 0x80, 0x7f, 0x81, 0x7f, 0x82, 0x80, 0x81, 0x81, + 0x83, 0x86, 0x80, 0x7f, 0x7f, 0x7e, 0x7f, 0x82, 0x83, 0x81, 0x80, + 0x84, 0x84, 0x83, 0x83, 0x84, 0x83, 0x7d, 0x7e, 0x7b, 0x79, 0x7c, + 0x7a, 0x74, 0x7b, 0x7f, 0x7c, 0x7b, 0x7c, 0x7e, 0x7a, 0x7a, 0x7a, + 0x7a, 0x78, 0x75, 0x77, 0x81, 0x86, 0x85, 0x85, 0x82, 0x7b, 0x73, + 0x71, 0x73, 0x77, 0x7a, 0x83, 0x86, 0x82, 0x84, 0x88, 0x88, 0x87, + 0x8b, 0x8b, 0x88, 0x8c, 0x90, 0x90, 0x92, 0x97, 0x95, 0x8f, 0x90, + 0x91, 0x8e, 0x8d, 0x8c, 0x85, 0x7d, 0x7a, 0x79, 0x7b, 0x7d, 0x7d, + 0x7a, 0x78, 0x72, 0x69, 0x65, 0x66, 0x68, 0x6c, 0x72, 0x6b, 0x61, + 0x5a, 0x55, 0x4e, 0x4e, 0x76, 0xae, 0xc7, 0xc3, 0xb4, 0x89, 0x59, + 0x4d, 0x58, 0x6d, 0x86, 0xa2, 0xa7, 0x95, 0x89, 0x86, 0x82, 0x81, + 0x87, 0x84, 0x7b, 0x7b, 0x82, 0x83, 0x88, 0x90, 0x90, 0x8a, 0x85, + 0x85, 0x84, 0x86, 0x8c, 0x8e, 0x88, 0x80, 0x7c, 0x79, 0x7c, 0x81, + 0x85, 0x85, 0x81, 0x78, 0x6d, 0x67, 0x68, 0x6e, 0x73, 0x73, 0x6f, + 0x67, 0x5e, 0x5a, 0x53, 0x58, 0x83, 0xb2, 0xc4, 0xbe, 0xa5, 0x74, + 0x4c, 0x4a, 0x5f, 0x7a, 0x97, 0xac, 0xa3, 0x8d, 0x82, 0x7c, 0x7a, + 0x84, 0x8d, 0x84, 0x7c, 0x7e, 0x80, 0x86, 0x94, 0x95, 0x8a, 0x83, + 0x80, 0x7e, 0x84, 0x8d, 0x8f, 0x8b, 0x85, 0x7b, 0x76, 0x7a, 0x81, + 0x87, 0x86, 0x81, 0x7c, 0x77, 0x70, 0x69, 0x6a, 0x6f, 0x72, 0x73, + 0x6d, 0x69, 0x62, 0x5f, 0x5d, 0x5b, 0x80, 0xb1, 0xc6, 0xc0, 0xa2, + 0x6f, 0x45, 0x45, 0x5f, 0x7f, 0x9f, 0xb0, 0x9f, 0x87, 0x7b, 0x78, + 0x7d, 0x8b, 0x92, 0x87, 0x7b, 0x7a, 0x7f, 0x88, 0x94, 0x95, 0x88, + 0x7c, 0x78, 0x7d, 0x89, 0x92, 0x91, 0x8e, 0x86, 0x7c, 0x75, 0x77, + 0x7c, 0x80, 0x86, 0x86, 0x81, 0x7e, 0x77, 0x6b, 0x66, 0x6d, 0x75, + 0x77, 0x77, 0x70, 0x68, 0x60, 0x5e, 0x56, 0x5b, 0x8b, 0xb7, 0xc4, + 0xb9, 0x98, 0x65, 0x46, 0x4f, 0x69, 0x89, 0xa5, 0xaa, 0x96, 0x84, + 0x7c, 0x79, 0x82, 0x8d, 0x8b, 0x80, 0x7a, 0x7b, 0x80, 0x8d, 0x9a, + 0x97, 0x88, 0x7a, 0x73, 0x78, 0x89, 0x94, 0x92, 0x8d, 0x84, 0x77, + 0x70, 0x78, 0x80, 0x83, 0x89, 0x8a, 0x82, 0x7b, 0x75, 0x6a, 0x64, + 0x6c, 0x70, 0x70, 0x73, 0x70, 0x6a, 0x66, 0x66, 0x5d, 0x69, 0x98, + 0xb8, 0xbb, 0xaa, 0x85, 0x57, 0x48, 0x5c, 0x7a, 0x99, 0xaa, 0xa2, + 0x89, 0x78, 0x74, 0x7c, 0x8a, 0x90, 0x8a, 0x81, 0x7c, 0x7d, 0x85, + 0x8e, 0x8e, 0x87, 0x7f, 0x7c, 0x80, 0x8b, 0x92, 0x91, 0x8a, 0x80, + 0x78, 0x77, 0x7d, 0x84, 0x87, 0x85, 0x81, 0x7b, 0x77, 0x72, 0x6d, + 0x6e, 0x72, 0x74, 0x71, 0x6c, 0x67, 0x64, 0x61, 0x65, 0x66, 0x61, + 0x82, 0xaf, 0xbd, 0xb3, 0x98, 0x69, 0x49, 0x54, 0x70, 0x8b, 0xa2, + 0xa8, 0x93, 0x81, 0x7c, 0x7a, 0x82, 0x8c, 0x8a, 0x7e, 0x78, 0x7c, + 0x85, 0x91, 0x9b, 0x93, 0x7e, 0x74, 0x76, 0x7a, 0x89, 0x97, 0x98, + 0x90, 0x85, 0x78, 0x72, 0x78, 0x80, 0x88, 0x8d, 0x88, 0x7f, 0x78, + 0x72, 0x6b, 0x67, 0x6c, 0x72, 0x72, 0x71, 0x6c, 0x65, 0x62, 0x62, + 0x60, 0x60, 0x62, 0x7b, 0xa7, 0xbc, 0xb4, 0x98, 0x70, 0x54, 0x59, + 0x71, 0x8c, 0x9f, 0xa2, 0x95, 0x84, 0x7c, 0x7b, 0x7f, 0x87, 0x88, + 0x7f, 0x7d, 0x81, 0x86, 0x8b, 0x8e, 0x89, 0x81, 0x7f, 0x82, 0x85, + 0x8a, 0x8e, 0x8a, 0x83, 0x80, 0x7f, 0x7f, 0x81, 0x87, 0x88, 0x87, + 0x86, 0x7f, 0x73, 0x6b, 0x6b, 0x6d, 0x72, 0x76, 0x73, 0x6c, 0x6a, + 0x6a, 0x68, 0x67, 0x66, 0x63, 0x61, 0x52, 0x5b, 0x92, 0xba, 0xc4, + 0xb3, 0x87, 0x52, 0x45, 0x5f, 0x80, 0x9f, 0xaf, 0xa1, 0x86, 0x7b, + 0x7c, 0x83, 0x8c, 0x8b, 0x84, 0x7b, 0x78, 0x81, 0x8b, 0x8e, 0x8c, + 0x86, 0x7e, 0x7e, 0x83, 0x86, 0x8a, 0x8a, 0x88, 0x85, 0x84, 0x81, + 0x7c, 0x7b, 0x7f, 0x84, 0x88, 0x89, 0x87, 0x81, 0x79, 0x72, 0x6c, + 0x6c, 0x70, 0x70, 0x6e, 0x6d, 0x6e, 0x6c, 0x67, 0x68, 0x65, 0x62, + 0x60, 0x59, 0x68, 0x88, 0xa9, 0xb6, 0xa7, 0x86, 0x61, 0x56, 0x65, + 0x81, 0x99, 0xa5, 0x99, 0x88, 0x7e, 0x7c, 0x84, 0x8c, 0x8b, 0x86, + 0x82, 0x80, 0x86, 0x89, 0x89, 0x86, 0x82, 0x82, 0x81, 0x80, 0x82, + 0x7f, 0x7b, 0x79, 0x7c, 0x84, 0x90, 0x95, 0x8f, 0x85, 0x7a, 0x76, + 0x7d, 0x86, 0x88, 0x84, 0x7f, 0x77, 0x72, 0x77, 0x7c, 0x7b, 0x7b, + 0x77, 0x6d, 0x65, 0x63, 0x64, 0x61, 0x61, 0x63, 0x65, 0x62, 0x60, + 0x5f, 0x5d, 0x85, 0xb5, 0xc1, 0xb4, 0x8f, 0x5a, 0x44, 0x5a, 0x7c, + 0x9f, 0xaf, 0xa0, 0x84, 0x76, 0x7b, 0x87, 0x91, 0x8f, 0x81, 0x75, + 0x79, 0x84, 0x8e, 0x92, 0x8d, 0x7f, 0x74, 0x73, 0x7a, 0x85, 0x88, + 0x84, 0x7d, 0x79, 0x7a, 0x7f, 0x87, 0x92, 0x98, 0x95, 0x86, 0x77, + 0x71, 0x76, 0x80, 0x89, 0x8c, 0x88, 0x7f, 0x77, 0x73, 0x72, 0x75, + 0x79, 0x76, 0x6f, 0x6a, 0x6c, 0x6e, 0x70, 0x70, 0x69, 0x69, 0x69, + 0x66, 0x63, 0x61, 0x57, 0x5a, 0x8f, 0xc3, 0xce, 0xb6, 0x89, 0x58, + 0x45, 0x61, 0x87, 0xa2, 0xac, 0xa0, 0x87, 0x7a, 0x7e, 0x83, 0x89, + 0x8a, 0x83, 0x7c, 0x7e, 0x85, 0x89, 0x88, 0x82, 0x79, 0x78, 0x80, + 0x88, 0x8a, 0x83, 0x78, 0x6f, 0x70, 0x79, 0x81, 0x85, 0x86, 0x85, + 0x83, 0x81, 0x7d, 0x7a, 0x7c, 0x82, 0x8a, 0x90, 0x94, 0x91, 0x85, + 0x79, 0x72, 0x73, 0x7e, 0x89, 0x8c, 0x85, 0x7b, 0x75, 0x72, 0x74, + 0x77, 0x77, 0x75, 0x71, 0x6e, 0x6f, 0x71, 0x74, 0x75, 0x74, 0x71, + 0x71, 0x72, 0x71, 0x6d, 0x66, 0x60, 0x5f, 0x79, 0xa9, 0xc5, 0xba, + 0x96, 0x6c, 0x52, 0x59, 0x78, 0x96, 0xa4, 0xa5, 0x96, 0x85, 0x7f, + 0x7e, 0x7c, 0x7a, 0x7c, 0x7e, 0x83, 0x8c, 0x8e, 0x89, 0x82, 0x7c, + 0x7c, 0x7e, 0x80, 0x80, 0x7e, 0x7c, 0x7c, 0x7d, 0x7e, 0x7d, 0x7c, + 0x81, 0x85, 0x85, 0x83, 0x80, 0x7d, 0x7c, 0x7d, 0x7e, 0x7e, 0x82, + 0x86, 0x8c, 0x96, 0x96, 0x87, 0x77, 0x71, 0x73, 0x7a, 0x83, 0x88, + 0x88, 0x83, 0x7b, 0x73, 0x71, 0x75, 0x7a, 0x7d, 0x7b, 0x75, 0x72, + 0x74, 0x77, 0x78, 0x74, 0x71, 0x6f, 0x71, 0x74, 0x73, 0x6f, 0x6f, + 0x73, 0x74, 0x71, 0x6c, 0x65, 0x6a, 0x86, 0xaa, 0xbd, 0xb0, 0x8e, + 0x6b, 0x5e, 0x68, 0x7d, 0x90, 0x9a, 0x9b, 0x96, 0x91, 0x89, 0x7e, + 0x74, 0x70, 0x75, 0x82, 0x8f, 0x92, 0x8e, 0x88, 0x7f, 0x7a, 0x7b, + 0x7e, 0x7f, 0x80, 0x81, 0x7f, 0x7b, 0x7a, 0x7a, 0x7c, 0x80, 0x81, + 0x81, 0x84, 0x86, 0x83, 0x7f, 0x7c, 0x7c, 0x7e, 0x82, 0x84, 0x83, + 0x8a, 0x94, 0x93, 0x85, 0x76, 0x71, 0x75, 0x80, 0x8a, 0x8b, 0x85, + 0x80, 0x7b, 0x76, 0x74, 0x77, 0x7a, 0x7c, 0x7d, 0x79, 0x75, 0x72, + 0x73, 0x75, 0x76, 0x75, 0x75, 0x74, 0x73, 0x74, 0x74, 0x71, 0x70, + 0x72, 0x73, 0x73, 0x71, 0x70, 0x70, 0x6f, 0x77, 0x8a, 0x9c, 0xa7, + 0xa8, 0x98, 0x80, 0x70, 0x6c, 0x73, 0x82, 0x94, 0x9e, 0x9e, 0x96, + 0x89, 0x7e, 0x79, 0x78, 0x78, 0x7d, 0x84, 0x8a, 0x8f, 0x90, 0x8c, + 0x84, 0x7c, 0x74, 0x72, 0x76, 0x7c, 0x83, 0x87, 0x85, 0x80, 0x7c, + 0x7c, 0x7e, 0x7f, 0x7f, 0x7e, 0x7e, 0x7f, 0x7f, 0x80, 0x80, 0x82, + 0x86, 0x89, 0x8a, 0x8a, 0x89, 0x85, 0x7f, 0x7b, 0x7b, 0x7c, 0x7e, + 0x80, 0x83, 0x84, 0x82, 0x7e, 0x78, 0x75, 0x74, 0x72, 0x73, 0x75, + 0x79, 0x7e, 0x7f, 0x7b, 0x75, 0x70, 0x6f, 0x70, 0x72, 0x74, 0x74, + 0x75, 0x76, 0x76, 0x73, 0x71, 0x74, 0x75, 0x73, 0x6e, 0x6d, 0x6c, + 0x72, 0x85, 0x9b, 0xac, 0xaa, 0x9e, 0x8e, 0x80, 0x77, 0x73, 0x78, + 0x83, 0x94, 0x9d, 0x9b, 0x93, 0x8d, 0x86, 0x7e, 0x76, 0x72, 0x77, + 0x81, 0x8a, 0x8d, 0x8d, 0x8c, 0x87, 0x80, 0x79, 0x76, 0x76, 0x79, + 0x7d, 0x7f, 0x80, 0x82, 0x82, 0x7f, 0x7c, 0x7d, 0x80, 0x7f, 0x7c, + 0x80, 0x82, 0x84, 0x87, 0x88, 0x83, 0x82, 0x85, 0x87, 0x83, 0x80, + 0x7e, 0x7e, 0x7e, 0x81, 0x81, 0x7e, 0x7e, 0x7e, 0x7c, 0x7a, 0x79, + 0x78, 0x76, 0x78, 0x77, 0x76, 0x77, 0x78, 0x78, 0x77, 0x76, 0x75, + 0x73, 0x72, 0x71, 0x6f, 0x6f, 0x70, 0x6f, 0x71, 0x75, 0x76, 0x72, + 0x6f, 0x71, 0x72, 0x70, 0x6e, 0x6f, 0x7a, 0x8d, 0xa1, 0xae, 0xa9, + 0x9c, 0x93, 0x8a, 0x7c, 0x71, 0x75, 0x81, 0x8c, 0x92, 0x96, 0x99, + 0x98, 0x90, 0x84, 0x7b, 0x76, 0x76, 0x78, 0x7d, 0x84, 0x89, 0x8b, + 0x8a, 0x87, 0x83, 0x7f, 0x7b, 0x76, 0x75, 0x76, 0x77, 0x79, 0x7e, + 0x83, 0x86, 0x85, 0x85, 0x84, 0x81, 0x7d, 0x7a, 0x7b, 0x7d, 0x7f, + 0x83, 0x85, 0x88, 0x8b, 0x87, 0x83, 0x84, 0x84, 0x81, 0x7e, 0x7c, + 0x7c, 0x7e, 0x7e, 0x7b, 0x7c, 0x7c, 0x79, 0x76, 0x75, 0x76, 0x78, + 0x77, 0x74, 0x76, 0x78, 0x75, 0x72, 0x72, 0x74, 0x70, 0x6e, 0x71, + 0x72, 0x74, 0x74, 0x72, 0x71, 0x74, 0x75, 0x72, 0x75, 0x78, 0x74, + 0x78, 0x7f, 0x81, 0x85, 0x8b, 0x98, 0xa6, 0xa8, 0x9b, 0x93, 0x91, + 0x8b, 0x82, 0x7d, 0x80, 0x88, 0x8c, 0x8e, 0x8e, 0x8f, 0x90, 0x8e, + 0x89, 0x83, 0x81, 0x7f, 0x7c, 0x7b, 0x7c, 0x7d, 0x7e, 0x81, 0x82, + 0x80, 0x7f, 0x7e, 0x7e, 0x7b, 0x7b, 0x7b, 0x7b, 0x7d, 0x7e, 0x80, + 0x7e, 0x7e, 0x7f, 0x7f, 0x80, 0x7d, 0x7e, 0x81, 0x85, 0x8d, 0x87, + 0x83, 0x88, 0x8b, 0x82, 0x78, 0x7d, 0x7e, 0x80, 0x7f, 0x7a, 0x7b, + 0x7e, 0x81, 0x79, 0x77, 0x79, 0x77, 0x75, 0x75, 0x77, 0x77, 0x7a, + 0x78, 0x73, 0x73, 0x74, 0x73, 0x70, 0x70, 0x70, 0x72, 0x75, 0x75, + 0x73, 0x72, 0x75, 0x73, 0x6e, 0x6d, 0x70, 0x74, 0x75, 0x75, 0x76, + 0x77, 0x7e, 0x8a, 0x9c, 0xa4, 0x9b, 0x99, 0xa0, 0xa5, 0x9b, 0x8e, + 0x8b, 0x8d, 0x90, 0x8b, 0x84, 0x81, 0x86, 0x8e, 0x8a, 0x83, 0x82, + 0x87, 0x8b, 0x88, 0x85, 0x83, 0x86, 0x87, 0x84, 0x80, 0x7c, 0x7f, + 0x7f, 0x7b, 0x78, 0x78, 0x7b, 0x7c, 0x7d, 0x7e, 0x7e, 0x80, 0x82, + 0x83, 0x82, 0x81, 0x82, 0x82, 0x83, 0x83, 0x82, 0x80, 0x7f, 0x7f, + 0x7f, 0x7e, 0x7f, 0x81, 0x82, 0x82, 0x82, 0x80, 0x7f, 0x7d, 0x7c, + 0x7b, 0x79, 0x78, 0x78, 0x78, 0x78, 0x77, 0x78, 0x79, 0x78, 0x79, + 0x7b, 0x7c, 0x7b, 0x7b, 0x7d, 0x7d, 0x7c, 0x7c, 0x7c, 0x7b, 0x7b, + 0x7c, 0x7c, 0x7b, 0x7c, 0x7c, 0x7c, 0x7a, 0x7a, 0x7b, 0x7d, 0x7d, + 0x7b, 0x7c, 0x7d, 0x7f, 0x7f, 0x80, 0x81, 0x81, 0x81, 0x82, 0x83, + 0x82, 0x82, 0x82, 0x83, 0x84, 0x86, 0x88, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x88, 0x87, 0x86, 0x85, 0x85, 0x84, 0x83, 0x82, 0x80, 0x80, + 0x7f, 0x7e, 0x7c, 0x7c, 0x7d, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7d, + 0x7d, 0x7e, 0x7e, 0x7e, 0x7e, 0x80, 0x80, 0x7e, 0x7e, 0x80, 0x80, + 0x7f, 0x7e, 0x7e, 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7d, + 0x7e, 0x7d, 0x7c, 0x7c, 0x7c, 0x7b, 0x7b, 0x7c, 0x7c, 0x7b, 0x7a, + 0x7a, 0x7b, 0x7c, 0x7b, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7b, 0x7b, + 0x7c, 0x7c, 0x7c, 0x7d, 0x7c, 0x7c, 0x7c, 0x7d, 0x7d, 0x7d, 0x7d, + 0x7d, 0x7d, 0x7d, 0x7c, 0x7d, 0x7d, 0x7d, 0x7e, 0x7f, 0x7f, 0x7f, + 0x80, 0x80, 0x81, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x89, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x87, 0x88, 0x88, 0x87, 0x86, 0x85, 0x85, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x82, 0x82, 0x82, 0x82, 0x80, 0x81, + 0x80, 0x7e, 0x7f, 0x7e, 0x7e, 0x7d, 0x7d, 0x7d, 0x7d, 0x7f, 0x7d, + 0x7c, 0x7d, 0x7b, 0x7c, 0x7c, 0x7a, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, + 0x7c, 0x7b, 0x7b, 0x7d, 0x7c, 0x79, 0x7d, 0x7d, 0x7a, 0x7a, 0x7a, + 0x7c, 0x7c, 0x7c, 0x7c, 0x7e, 0x81, 0x7e, 0x7d, 0x7d, 0x7f, 0x80, + 0x7e, 0x7e, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x81, 0x81, + 0x81, 0x82, 0x81, 0x82, 0x81, 0x80, 0x82, 0x82, 0x82, 0x81, 0x81, + 0x82, 0x82, 0x81, 0x81, 0x81, 0x83, 0x82, 0x80, 0x82, 0x82, 0x82, + 0x81, 0x81, 0x81, 0x82, 0x83, 0x82, 0x81, 0x82, 0x80, 0x82, 0x83, + 0x80, 0x80, 0x82, 0x81, 0x80, 0x81, 0x81, 0x82, 0x81, 0x80, 0x82, + 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x7d, 0x80, 0x7e, 0x7b, + 0x7d, 0x7f, 0x7e, 0x7e, 0x7c, 0x7d, 0x80, 0x7e, 0x7e, 0x7f, 0x7f, + 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x7d, 0x7e, 0x7e, 0x7f, + 0x7f, 0x7e, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x7f, + 0x80, 0x7f, 0x7f, 0x7f, 0x7e, 0x7e, 0x7f, 0x7f, 0x7e, 0x7f, 0x80, + 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x81, 0x7f, 0x80, 0x81, 0x81, + 0x82, 0x7f, 0x7f, 0x81, 0x81, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x7f, + 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x81, 0x80, 0x80, 0x81, 0x81, + 0x7f, 0x7e, 0x81, 0x80, 0x7e, 0x7e, 0x7f, 0x7f, 0x80, 0x7e, 0x7e, + 0x80, 0x82, 0x80, 0x7f, 0x7f, 0x81, 0x80, 0x7f, 0x81, 0x7e, 0x7e, + 0x81, 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x82, 0x7f, 0x7e, 0x82, 0x7f, + 0x7e, 0x7f, 0x7e, 0x81, 0x80, 0x7e, 0x7f, 0x7e, 0x7f, 0x7f, 0x7e, + 0x80, 0x82, 0x7f, 0x7e, 0x80, 0x7f, 0x81, 0x7f, 0x7d, 0x80, 0x83, + 0x83, 0x7c, 0x81, 0x82, 0x7e, 0x82, 0x7d, 0x7f, 0x80, 0x80, 0x80, + 0x7f, 0x82, 0x7f, 0x81, 0x7e, 0x80, 0x81, 0x7c, 0x80, 0x81, 0x7f, + 0x80, 0x81, 0x7f, 0x7f, 0x80, 0x80, 0x7e, 0x7f, 0x7f, 0x7f, 0x81, + 0x81, 0x7e, 0x7c, 0x81, 0x7f, 0x7f, 0x7f, 0x7e, 0x80, 0x81, 0x7f, + 0x7d, 0x80, 0x80, 0x7f, 0x81, 0x80, 0x80, 0x7f, 0x7e, 0x80, 0x81, + 0x7e, 0x7f, 0x80, 0x7e, 0x7f, 0x7f, 0x7d, 0x7e, 0x7e, 0x7d, 0x80, + 0x80, 0x81, 0x82, 0x80, 0x7f, 0x81, 0x81, 0x7e, 0x81, 0x81, 0x7e, + 0x81, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x81, 0x80, + 0x7f, 0x81, 0x81, 0x7e, 0x7f, 0x81, 0x7f, 0x7f, 0x7e, 0x80, 0x80, + 0x7f, 0x7f, 0x80, 0x81, 0x80, 0x81, 0x7f, 0x7e, 0x7f, 0x80, 0x7f, + 0x7d, 0x7e, 0x80, 0x80, 0x7e, 0x81, 0x7f, 0x7f, 0x81, 0x7f, 0x81, + 0x81, 0x80, 0x80, 0x81, 0x80, 0x7e, 0x7f, 0x7f, 0x7e, 0x80, 0x80, + 0x7d, 0x80, 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x81, + 0x7f, 0x7e, 0x7f, 0x7e, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, + 0x80, 0x80, 0x81, 0x81, 0x80, 0x80, 0x7f, 0x7f, 0x7d, 0x7e, 0x81, + 0x7f, 0x7e, 0x7f, 0x81, 0x80, 0x7f, 0x7f, 0x7f, 0x81, 0x82, 0x80, + 0x80, 0x80, 0x81, 0x80, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7e, + 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7e, 0x7f, 0x80, 0x81, 0x7f, 0x81, + 0x81, 0x7f, 0x80, 0x7e, 0x7e, 0x7f, 0x7f, 0x80, 0x81, 0x80, 0x80, + 0x81, 0x80, 0x7e, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7e, 0x7f, 0x81, + 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7e, 0x80, 0x7f, 0x81, 0x80, 0x7f, 0x81, 0x81, + 0x7f, 0x7f, 0x7f, 0x7f, 0x81, 0x7f, 0x7f, 0x80, 0x81, 0x80, 0x7e, + 0x7e, 0x80, 0x81, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7f, + 0x80, 0x81, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, + 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, + 0x80, 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, + 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x7f, + 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x7f, + 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, + 0x80, + }, + { // 6 + 0x80, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, + 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, + 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, + 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x80, + 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, + 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, + 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x7f, + 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, + 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, + 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, + 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x80, + 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x7e, 0x80, + 0x7f, 0x80, 0x81, 0x7e, 0x80, 0x7f, 0x81, 0x7e, 0x80, 0x7f, 0x7f, + 0x81, 0x7e, 0x7f, 0x7f, 0x81, 0x7e, 0x80, 0x7f, 0x81, 0x7e, 0x80, + 0x80, 0x7e, 0x82, 0x7e, 0x81, 0x7f, 0x81, 0x7f, 0x81, 0x7e, 0x80, + 0x7f, 0x7f, 0x80, 0x7e, 0x83, 0x7f, 0x83, 0x7c, 0x81, 0x7e, 0x81, + 0x7e, 0x80, 0x80, 0x7e, 0x81, 0x7c, 0x84, 0x7b, 0x83, 0x7c, 0x82, + 0x80, 0x80, 0x80, 0x7e, 0x81, 0x7d, 0x81, 0x7f, 0x80, 0x7f, 0x80, + 0x7f, 0x81, 0x7e, 0x81, 0x7d, 0x81, 0x7d, 0x81, 0x7d, 0x82, 0x7e, + 0x80, 0x81, 0x7f, 0x80, 0x7f, 0x81, 0x7d, 0x81, 0x7d, 0x82, 0x7f, + 0x81, 0x7e, 0x81, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7e, 0x7f, 0x7f, + 0x80, 0x7f, 0x7e, 0x81, 0x7f, 0x80, 0x7f, 0x81, 0x81, 0x80, 0x80, + 0x80, 0x7f, 0x7f, 0x7e, 0x7e, 0x80, 0x7f, 0x7f, 0x80, 0x7e, 0x81, + 0x80, 0x7f, 0x82, 0x7e, 0x83, 0x7e, 0x80, 0x7e, 0x82, 0x80, 0x7f, + 0x7e, 0x7f, 0x81, 0x7e, 0x81, 0x7d, 0x82, 0x7c, 0x82, 0x7d, 0x80, + 0x83, 0x7c, 0x82, 0x7d, 0x84, 0x80, 0x7f, 0x81, 0x7e, 0x81, 0x7d, + 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x7d, 0x80, 0x7e, + 0x85, 0x7e, 0x81, 0x7f, 0x7d, 0x83, 0x7b, 0x83, 0x7d, 0x80, 0x7f, + 0x7e, 0x81, 0x7e, 0x83, 0x7d, 0x82, 0x7f, 0x7f, 0x80, 0x7f, 0x80, + 0x7e, 0x81, 0x7c, 0x83, 0x7e, 0x80, 0x81, 0x7f, 0x81, 0x7e, 0x82, + 0x7c, 0x82, 0x7f, 0x7d, 0x83, 0x7d, 0x82, 0x7e, 0x7f, 0x7f, 0x80, + 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7e, 0x81, 0x7f, 0x82, 0x7e, 0x80, + 0x81, 0x7e, 0x82, 0x7e, 0x7f, 0x81, 0x7e, 0x7f, 0x7f, 0x80, 0x82, + 0x7e, 0x7f, 0x7f, 0x7f, 0x81, 0x7e, 0x81, 0x80, 0x80, 0x80, 0x7e, + 0x7f, 0x81, 0x81, 0x7f, 0x80, 0x7f, 0x81, 0x7e, 0x81, 0x7f, 0x80, + 0x81, 0x7e, 0x81, 0x7d, 0x81, 0x7e, 0x80, 0x81, 0x7d, 0x84, 0x7e, + 0x80, 0x7f, 0x7e, 0x82, 0x7e, 0x81, 0x7f, 0x7e, 0x81, 0x81, 0x7c, + 0x80, 0x81, 0x7f, 0x82, 0x7d, 0x81, 0x7f, 0x81, 0x7f, 0x7e, 0x81, + 0x7f, 0x80, 0x7d, 0x81, 0x7f, 0x7f, 0x7f, 0x7e, 0x80, 0x80, 0x81, + 0x80, 0x7f, 0x80, 0x81, 0x7d, 0x7f, 0x80, 0x7e, 0x81, 0x7e, 0x80, + 0x80, 0x81, 0x7f, 0x7f, 0x80, 0x7e, 0x80, 0x7f, 0x81, 0x7f, 0x81, + 0x7e, 0x80, 0x7e, 0x7d, 0x82, 0x7d, 0x82, 0x7f, 0x7d, 0x83, 0x7f, + 0x7d, 0x82, 0x7e, 0x81, 0x81, 0x7b, 0x82, 0x80, 0x7e, 0x81, 0x7c, + 0x82, 0x82, 0x7c, 0x80, 0x7f, 0x81, 0x80, 0x7f, 0x7f, 0x7f, 0x81, + 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x7e, 0x7e, 0x82, 0x80, 0x80, + 0x7e, 0x80, 0x80, 0x7d, 0x82, 0x7e, 0x81, 0x82, 0x7c, 0x81, 0x7e, + 0x80, 0x81, 0x7d, 0x83, 0x80, 0x7f, 0x7f, 0x81, 0x7e, 0x81, 0x7f, + 0x7f, 0x82, 0x7d, 0x80, 0x7f, 0x7d, 0x82, 0x7e, 0x7f, 0x81, 0x7e, + 0x83, 0x7c, 0x80, 0x80, 0x81, 0x80, 0x7e, 0x80, 0x7e, 0x82, 0x7d, + 0x81, 0x7f, 0x81, 0x80, 0x7b, 0x81, 0x7e, 0x83, 0x7d, 0x7e, 0x80, + 0x7f, 0x81, 0x7c, 0x7d, 0x82, 0x7f, 0x80, 0x7f, 0x80, 0x81, 0x80, + 0x82, 0x7c, 0x82, 0x80, 0x7c, 0x82, 0x7d, 0x7f, 0x7e, 0x82, 0x80, + 0x7b, 0x84, 0x82, 0x82, 0x84, 0x7d, 0x7e, 0x85, 0x7f, 0x7f, 0x7c, + 0x80, 0x82, 0x7a, 0x84, 0x7a, 0x82, 0x84, 0x7c, 0x82, 0x7c, 0x85, + 0x7f, 0x83, 0x80, 0x7f, 0x85, 0x81, 0x82, 0x7c, 0x82, 0x80, 0x80, + 0x80, 0x7c, 0x84, 0x7f, 0x80, 0x81, 0x7d, 0x81, 0x80, 0x7e, 0x7f, + 0x7e, 0x7e, 0x7c, 0x7b, 0x7a, 0x76, 0x79, 0x75, 0x74, 0x75, 0x6f, + 0x70, 0x6e, 0x6a, 0x68, 0x68, 0x70, 0x79, 0x81, 0x82, 0x8d, 0x95, + 0x99, 0xa0, 0x9e, 0x9d, 0xa1, 0xa0, 0x99, 0x92, 0x8a, 0x84, 0x80, + 0x75, 0x6e, 0x6f, 0x71, 0x72, 0x74, 0x7a, 0x86, 0x92, 0x9c, 0xa1, + 0xa9, 0xaf, 0xac, 0xa5, 0x9c, 0x96, 0x89, 0x7d, 0x70, 0x65, 0x62, + 0x5b, 0x55, 0x52, 0x55, 0x58, 0x5a, 0x5b, 0x5c, 0x60, 0x5d, 0x59, + 0x54, 0x52, 0x4d, 0x4d, 0x51, 0x56, 0x7c, 0x92, 0x8c, 0x98, 0xae, + 0xb5, 0xb3, 0xb2, 0xaa, 0xaa, 0xab, 0x97, 0x85, 0x81, 0x77, 0x6e, + 0x6b, 0x66, 0x69, 0x75, 0x7d, 0x80, 0x8d, 0x99, 0x9d, 0xa2, 0xa3, + 0x9f, 0x9b, 0x94, 0x89, 0x82, 0x7a, 0x71, 0x6e, 0x6f, 0x70, 0x76, + 0x7e, 0x84, 0x8b, 0x8e, 0x8d, 0x8b, 0x87, 0x7f, 0x79, 0x71, 0x68, + 0x62, 0x5e, 0x5b, 0x57, 0x57, 0x57, 0x55, 0x53, 0x4f, 0x57, 0x89, + 0xa0, 0x8a, 0x93, 0xb1, 0xb7, 0xaf, 0xa3, 0x95, 0x9e, 0x9f, 0x81, + 0x6e, 0x75, 0x75, 0x70, 0x6d, 0x66, 0x74, 0x89, 0x87, 0x82, 0x96, + 0xa4, 0x9f, 0x9b, 0x96, 0x94, 0x94, 0x88, 0x75, 0x71, 0x74, 0x6e, + 0x6b, 0x6c, 0x71, 0x7b, 0x82, 0x84, 0x8b, 0x91, 0x91, 0x8f, 0x86, + 0x80, 0x7b, 0x73, 0x71, 0x6f, 0x6b, 0x73, 0x77, 0x71, 0x75, 0x71, + 0x6e, 0x6d, 0x61, 0x55, 0x54, 0x4b, 0x41, 0x76, 0x9c, 0x85, 0x8f, + 0xb2, 0xbc, 0xb9, 0xb2, 0x9f, 0xa0, 0xa4, 0x84, 0x68, 0x6b, 0x69, + 0x5f, 0x60, 0x63, 0x71, 0x8c, 0x96, 0x8d, 0x9a, 0xad, 0xa5, 0x9a, + 0x91, 0x8a, 0x84, 0x77, 0x64, 0x60, 0x6b, 0x6b, 0x66, 0x71, 0x80, + 0x88, 0x92, 0x96, 0x97, 0x9d, 0x99, 0x8a, 0x7f, 0x7d, 0x7b, 0x73, + 0x71, 0x72, 0x73, 0x78, 0x7d, 0x7b, 0x7e, 0x87, 0x86, 0x80, 0x7c, + 0x75, 0x71, 0x70, 0x65, 0x5e, 0x61, 0x62, 0x5c, 0x5a, 0x58, 0x5e, + 0x92, 0xab, 0x91, 0x92, 0xb2, 0xb6, 0xa1, 0x98, 0x87, 0x86, 0x8d, + 0x6f, 0x5c, 0x74, 0x80, 0x76, 0x7a, 0x88, 0x93, 0x9d, 0x97, 0x8b, + 0x96, 0x9a, 0x87, 0x79, 0x7b, 0x7c, 0x76, 0x6d, 0x6b, 0x78, 0x81, + 0x7a, 0x78, 0x80, 0x85, 0x86, 0x81, 0x7e, 0x84, 0x8b, 0x86, 0x83, + 0x88, 0x88, 0x84, 0x82, 0x81, 0x80, 0x82, 0x81, 0x7b, 0x7c, 0x7f, + 0x7c, 0x79, 0x78, 0x78, 0x78, 0x77, 0x75, 0x75, 0x78, 0x75, 0x6f, + 0x71, 0x71, 0x6b, 0x6b, 0x6b, 0x68, 0x67, 0x67, 0x6b, 0x92, 0xb0, + 0x9d, 0x94, 0xae, 0xb2, 0x97, 0x8b, 0x7d, 0x78, 0x83, 0x73, 0x61, + 0x73, 0x85, 0x81, 0x7e, 0x89, 0x93, 0x9c, 0x98, 0x86, 0x86, 0x8f, + 0x84, 0x72, 0x75, 0x7d, 0x78, 0x76, 0x76, 0x7d, 0x86, 0x83, 0x7b, + 0x81, 0x8a, 0x85, 0x7e, 0x7d, 0x7d, 0x7d, 0x7c, 0x7a, 0x7f, 0x83, + 0x81, 0x81, 0x88, 0x8a, 0x85, 0x83, 0x84, 0x85, 0x83, 0x7f, 0x7d, + 0x7d, 0x7c, 0x7a, 0x7a, 0x7a, 0x79, 0x78, 0x79, 0x79, 0x78, 0x78, + 0x78, 0x76, 0x75, 0x75, 0x76, 0x75, 0x76, 0x76, 0x70, 0x71, 0x75, + 0x6e, 0x6b, 0x6c, 0x6d, 0x64, 0x77, 0xab, 0xa7, 0x8b, 0x97, 0xba, + 0xa7, 0x84, 0x89, 0x90, 0x88, 0x7a, 0x7c, 0x78, 0x7f, 0x88, 0x81, + 0x7e, 0x8c, 0x95, 0x8b, 0x83, 0x86, 0x8f, 0x88, 0x7e, 0x7c, 0x83, + 0x82, 0x78, 0x75, 0x7a, 0x82, 0x7c, 0x74, 0x77, 0x7f, 0x7f, 0x7b, + 0x7f, 0x84, 0x84, 0x7f, 0x7d, 0x80, 0x81, 0x81, 0x81, 0x82, 0x84, + 0x87, 0x86, 0x84, 0x83, 0x83, 0x81, 0x7d, 0x7e, 0x7f, 0x7e, 0x7c, + 0x7b, 0x7a, 0x7b, 0x7b, 0x7a, 0x79, 0x79, 0x79, 0x78, 0x78, 0x78, + 0x77, 0x78, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x78, 0x78, 0x77, + 0x75, 0x77, 0x76, 0x73, 0x6f, 0x75, 0x81, 0x7d, 0x77, 0x87, 0x9b, + 0x93, 0x88, 0x92, 0x9e, 0x93, 0x85, 0x8c, 0x92, 0x87, 0x7e, 0x82, + 0x85, 0x81, 0x7e, 0x81, 0x83, 0x85, 0x87, 0x86, 0x85, 0x86, 0x89, + 0x83, 0x7f, 0x81, 0x83, 0x7c, 0x78, 0x7b, 0x7c, 0x78, 0x76, 0x7a, + 0x7d, 0x7e, 0x7e, 0x7f, 0x82, 0x83, 0x81, 0x7e, 0x7e, 0x7e, 0x7d, + 0x7b, 0x7c, 0x7e, 0x7c, 0x7b, 0x7c, 0x7e, 0x7e, 0x7e, 0x7f, 0x80, + 0x7f, 0x7f, 0x7e, 0x7d, 0x7d, 0x7d, 0x7c, 0x7c, 0x7c, 0x7d, 0x7d, + 0x7d, 0x7e, 0x7e, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, + 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, + 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x81, 0x81, 0x81, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x81, 0x81, 0x81, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, + 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, + 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, + 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, + 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, + 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x80, + 0x80, 0x7f, 0x7e, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x81, 0x81, 0x80, + 0x7f, 0x80, 0x80, 0x81, 0x82, 0x82, 0x81, 0x7f, 0x7e, 0x7e, 0x7e, + 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x82, 0x7f, 0x83, 0x85, 0x82, 0x7c, + 0x7a, 0x7d, 0x80, 0x7e, 0x7c, 0x7c, 0x7e, 0x7f, 0x7f, 0x7f, 0x7e, + 0x7e, 0x7f, 0x7f, 0x80, 0x80, 0x7e, 0x81, 0x81, 0x80, 0x7d, 0x7e, + 0x81, 0x82, 0x7f, 0x7b, 0x7e, 0x80, 0x82, 0x7f, 0x7d, 0x7f, 0x82, + 0x84, 0x81, 0x81, 0x7d, 0x82, 0x83, 0x7f, 0x81, 0x80, 0x84, 0x83, + 0x82, 0x83, 0x81, 0x81, 0x80, 0x7e, 0x7d, 0x7e, 0x80, 0x81, 0x7e, + 0x7b, 0x7d, 0x83, 0x80, 0x7f, 0x7d, 0x81, 0x83, 0x80, 0x80, 0x7e, + 0x7d, 0x82, 0x81, 0x7d, 0x7c, 0x80, 0x83, 0x7f, 0x7f, 0x7a, 0x81, + 0x81, 0x82, 0x7f, 0x7c, 0x80, 0x81, 0x85, 0x7b, 0x7d, 0x81, 0x82, + 0x80, 0x7c, 0x7e, 0x80, 0x86, 0x80, 0x7d, 0x7c, 0x82, 0x88, 0x7c, + 0x7c, 0x7d, 0x82, 0x83, 0x7e, 0x7c, 0x7e, 0x80, 0x83, 0x80, 0x7a, + 0x7f, 0x81, 0x85, 0x7f, 0x7b, 0x7e, 0x7f, 0x82, 0x81, 0x7b, 0x7e, + 0x82, 0x81, 0x81, 0x79, 0x81, 0x81, 0x83, 0x7f, 0x7d, 0x80, 0x80, + 0x84, 0x78, 0x7f, 0x7e, 0x83, 0x7e, 0x7c, 0x7f, 0x81, 0x85, 0x7c, + 0x7c, 0x7e, 0x85, 0x81, 0x7f, 0x7a, 0x85, 0x82, 0x80, 0x7f, 0x77, + 0x81, 0x81, 0x81, 0x7d, 0x7c, 0x81, 0x83, 0x81, 0x7a, 0x81, 0x82, + 0x83, 0x7d, 0x7c, 0x82, 0x80, 0x81, 0x7a, 0x80, 0x80, 0x80, 0x7e, + 0x7c, 0x82, 0x7f, 0x82, 0x7c, 0x7f, 0x81, 0x81, 0x80, 0x7b, 0x81, + 0x81, 0x81, 0x7d, 0x80, 0x7e, 0x82, 0x80, 0x7c, 0x80, 0x7d, 0x84, + 0x7f, 0x7f, 0x7f, 0x80, 0x81, 0x7f, 0x80, 0x7d, 0x82, 0x7e, 0x82, + 0x7d, 0x7e, 0x82, 0x7f, 0x80, 0x7d, 0x7f, 0x80, 0x80, 0x80, 0x7f, + 0x7f, 0x83, 0x80, 0x80, 0x7e, 0x7f, 0x82, 0x7e, 0x80, 0x7f, 0x80, + 0x81, 0x7e, 0x7e, 0x7f, 0x7f, 0x81, 0x81, 0x80, 0x80, 0x7e, 0x83, + 0x7f, 0x7e, 0x7e, 0x7e, 0x84, 0x7b, 0x7f, 0x80, 0x7e, 0x83, 0x7e, + 0x80, 0x7e, 0x83, 0x81, 0x7e, 0x7f, 0x7e, 0x84, 0x7e, 0x7d, 0x80, + 0x7f, 0x81, 0x7e, 0x7e, 0x7f, 0x82, 0x81, 0x7f, 0x7f, 0x7f, 0x82, + 0x7e, 0x80, 0x7e, 0x80, 0x81, 0x7e, 0x7f, 0x80, 0x7e, 0x80, 0x81, + 0x7d, 0x81, 0x7e, 0x83, 0x7f, 0x7f, 0x81, 0x7c, 0x82, 0x7e, 0x81, + 0x7d, 0x81, 0x81, 0x80, 0x7f, 0x7d, 0x82, 0x7e, 0x81, 0x7e, 0x7f, + 0x82, 0x7e, 0x81, 0x7d, 0x80, 0x81, 0x7e, 0x82, 0x7f, 0x7f, 0x7f, + 0x81, 0x80, 0x7e, 0x81, 0x7f, 0x7e, 0x80, 0x82, 0x7e, 0x7d, 0x80, + 0x82, 0x7d, 0x7c, 0x82, 0x7f, 0x81, 0x7e, 0x80, 0x81, 0x7c, 0x80, + 0x7f, 0x80, 0x80, 0x7d, 0x83, 0x7f, 0x80, 0x7f, 0x7d, 0x82, 0x7d, + 0x81, 0x80, 0x7f, 0x7f, 0x80, 0x81, 0x7e, 0x80, 0x80, 0x7e, 0x80, + 0x81, 0x80, 0x7d, 0x7f, 0x82, 0x7e, 0x7d, 0x81, 0x80, 0x81, 0x7e, + 0x80, 0x81, 0x7e, 0x81, 0x7f, 0x7f, 0x82, 0x7f, 0x80, 0x7f, 0x80, + 0x80, 0x80, 0x7e, 0x7e, 0x82, 0x7e, 0x80, 0x7e, 0x80, 0x81, 0x7f, + 0x80, 0x7d, 0x80, 0x81, 0x7f, 0x7f, 0x7f, 0x81, 0x81, 0x7e, 0x80, + 0x7d, 0x82, 0x7f, 0x7f, 0x7f, 0x7e, 0x81, 0x7f, 0x7f, 0x7f, 0x80, + 0x7f, 0x80, 0x7f, 0x81, 0x7f, 0x7e, 0x80, 0x7f, 0x80, 0x7f, 0x80, + 0x7f, 0x7d, 0x80, 0x7f, 0x80, 0x7f, 0x81, 0x7f, 0x7f, 0x7e, 0x81, + 0x7d, 0x82, 0x7e, 0x7e, 0x81, 0x7e, 0x83, 0x7c, 0x81, 0x7f, 0x80, + 0x80, 0x7e, 0x81, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x80, + 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, + 0x80, 0x7f, 0x80, 0x80, 0x7e, 0x80, 0x80, 0x80, 0x80, 0x7e, 0x80, + 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, + 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x81, 0x7f, 0x7f, 0x81, 0x7e, 0x82, + 0x7d, 0x80, 0x80, 0x7f, 0x81, 0x7e, 0x80, 0x7f, 0x80, 0x80, 0x7e, + 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x81, 0x7f, 0x80, + 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x81, 0x7e, 0x81, 0x7e, + 0x80, 0x7f, 0x7f, 0x81, 0x7e, 0x81, 0x7f, 0x81, 0x7f, 0x80, 0x7f, + 0x81, 0x7f, 0x7f, 0x80, 0x7e, 0x81, 0x7f, 0x80, 0x7e, 0x80, 0x7f, + 0x7f, 0x7f, 0x80, 0x81, 0x7e, 0x80, 0x7f, 0x80, 0x80, 0x7e, 0x81, + 0x7f, 0x80, 0x80, 0x7e, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, + 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x81, 0x7f, 0x80, 0x7f, 0x7f, 0x80, + 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x80, + 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x80, + 0x7f, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x7f, + 0x7f, 0x80, 0x80, 0x7e, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x80, + 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, + 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, + 0x7e, 0x80, 0x80, 0x7f, 0x7f, 0x7e, 0x80, 0x7f, 0x7f, 0x80, 0x7e, + 0x80, 0x81, 0x80, 0x81, 0x81, 0x82, 0x81, 0x80, 0x80, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, 0x7f, + 0x7e, 0x7e, 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x7d, 0x7d, 0x7d, 0x7d, + 0x7d, 0x7e, 0x7d, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, + 0x80, 0x7f, 0x80, 0x80, 0x81, 0x81, 0x81, 0x82, 0x81, 0x81, 0x81, + 0x80, 0x81, 0x81, 0x81, 0x80, 0x80, 0x81, 0x80, 0x80, 0x7f, 0x7f, + 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x80, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, + 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x7f, + 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, + 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x80, + 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x80, + 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, + 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, + 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, + }, + { // 7 + 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x80, + 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, + 0x80, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, + 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, + 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, + 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, + 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x7f, + 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, + 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, + 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, + 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x80, + 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x7e, 0x80, + 0x7f, 0x80, 0x81, 0x7e, 0x80, 0x7f, 0x81, 0x7e, 0x80, 0x7f, 0x7f, + 0x81, 0x7e, 0x7f, 0x7f, 0x81, 0x7e, 0x80, 0x7f, 0x81, 0x7e, 0x80, + 0x80, 0x7e, 0x82, 0x7e, 0x81, 0x7f, 0x81, 0x7f, 0x81, 0x7e, 0x80, + 0x7f, 0x7f, 0x80, 0x7e, 0x83, 0x7f, 0x83, 0x7c, 0x81, 0x7e, 0x81, + 0x7e, 0x80, 0x80, 0x7e, 0x81, 0x7c, 0x84, 0x7b, 0x83, 0x7c, 0x82, + 0x80, 0x80, 0x80, 0x7e, 0x81, 0x7d, 0x81, 0x7f, 0x80, 0x7f, 0x80, + 0x7f, 0x81, 0x7e, 0x81, 0x7d, 0x81, 0x7d, 0x81, 0x7d, 0x82, 0x7e, + 0x80, 0x81, 0x7f, 0x80, 0x7f, 0x81, 0x7d, 0x81, 0x7d, 0x82, 0x7f, + 0x81, 0x7e, 0x81, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7e, 0x7f, 0x7f, + 0x80, 0x7f, 0x7e, 0x81, 0x7f, 0x80, 0x7f, 0x81, 0x81, 0x80, 0x80, + 0x80, 0x7f, 0x7f, 0x7e, 0x7e, 0x80, 0x7f, 0x7f, 0x80, 0x7e, 0x81, + 0x80, 0x7f, 0x82, 0x7e, 0x83, 0x7e, 0x80, 0x7e, 0x82, 0x80, 0x7f, + 0x7e, 0x7f, 0x81, 0x7e, 0x81, 0x7d, 0x82, 0x7c, 0x82, 0x7d, 0x80, + 0x83, 0x7c, 0x82, 0x7d, 0x84, 0x80, 0x7f, 0x81, 0x7e, 0x81, 0x7d, + 0x7f, 0x80, 0x7f, 0x80, 0x81, 0x7f, 0x80, 0x7f, 0x7d, 0x80, 0x7e, + 0x85, 0x7d, 0x81, 0x7f, 0x7e, 0x83, 0x7b, 0x83, 0x7d, 0x81, 0x7e, + 0x7e, 0x80, 0x7e, 0x83, 0x7d, 0x83, 0x7e, 0x80, 0x7f, 0x7f, 0x81, + 0x7d, 0x82, 0x7b, 0x83, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x81, + 0x7c, 0x82, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x7e, 0x80, + 0x80, 0x81, 0x7e, 0x7f, 0x81, 0x80, 0x7e, 0x81, 0x80, 0x7f, 0x81, + 0x7c, 0x81, 0x7f, 0x81, 0x81, 0x7f, 0x80, 0x7e, 0x81, 0x7d, 0x7e, + 0x81, 0x7f, 0x81, 0x81, 0x7c, 0x81, 0x7f, 0x7e, 0x82, 0x7e, 0x81, + 0x81, 0x7e, 0x81, 0x7e, 0x81, 0x80, 0x7e, 0x7f, 0x7f, 0x7f, 0x7d, + 0x82, 0x7f, 0x80, 0x81, 0x80, 0x7f, 0x7e, 0x7f, 0x80, 0x7f, 0x80, + 0x81, 0x7f, 0x7f, 0x80, 0x7e, 0x7e, 0x81, 0x7e, 0x81, 0x81, 0x7f, + 0x7f, 0x7d, 0x82, 0x7e, 0x7f, 0x81, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, + 0x80, 0x80, 0x7e, 0x80, 0x81, 0x7d, 0x80, 0x80, 0x7e, 0x80, 0x80, + 0x80, 0x80, 0x7f, 0x82, 0x7e, 0x7f, 0x81, 0x7d, 0x82, 0x80, 0x7f, + 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x7e, 0x7f, + 0x80, 0x7f, 0x80, 0x82, 0x7f, 0x7f, 0x81, 0x7f, 0x7f, 0x7e, 0x80, + 0x7f, 0x7f, 0x81, 0x7e, 0x81, 0x80, 0x7e, 0x80, 0x7f, 0x7f, 0x80, + 0x81, 0x7d, 0x7f, 0x82, 0x81, 0x80, 0x7d, 0x7f, 0x82, 0x7f, 0x7f, + 0x80, 0x7e, 0x82, 0x7e, 0x7e, 0x80, 0x80, 0x7f, 0x81, 0x7e, 0x7d, + 0x82, 0x7b, 0x83, 0x7e, 0x7f, 0x83, 0x7f, 0x82, 0x7d, 0x80, 0x80, + 0x7f, 0x7f, 0x7d, 0x82, 0x7e, 0x80, 0x81, 0x7e, 0x81, 0x7e, 0x7f, + 0x81, 0x7e, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7e, 0x80, 0x81, + 0x81, 0x7e, 0x7e, 0x81, 0x7e, 0x7f, 0x81, 0x7e, 0x80, 0x81, 0x7e, + 0x7f, 0x80, 0x81, 0x7c, 0x82, 0x7e, 0x7f, 0x7f, 0x7e, 0x80, 0x7f, + 0x84, 0x7e, 0x82, 0x80, 0x7d, 0x83, 0x7e, 0x7e, 0x7f, 0x80, 0x81, + 0x7d, 0x83, 0x81, 0x7e, 0x81, 0x7d, 0x7e, 0x82, 0x7d, 0x7d, 0x80, + 0x7e, 0x7e, 0x82, 0x7f, 0x7e, 0x80, 0x80, 0x80, 0x7f, 0x7d, 0x80, + 0x80, 0x81, 0x7f, 0x7e, 0x83, 0x81, 0x80, 0x81, 0x7f, 0x81, 0x7f, + 0x7f, 0x7f, 0x7d, 0x7f, 0x7e, 0x7c, 0x7c, 0x7e, 0x7e, 0x81, 0x7f, + 0x80, 0x81, 0x80, 0x7f, 0x83, 0x82, 0x7f, 0x81, 0x80, 0x80, 0x7f, + 0x7f, 0x82, 0x82, 0x84, 0x85, 0x85, 0x86, 0x85, 0x86, 0x85, 0x85, + 0x85, 0x82, 0x83, 0x82, 0x7f, 0x7e, 0x80, 0x7f, 0x7e, 0x7e, 0x7b, + 0x79, 0x7b, 0x79, 0x76, 0x72, 0x6f, 0x6c, 0x69, 0x67, 0x60, 0x5e, + 0x5f, 0x5c, 0x58, 0x57, 0x56, 0x57, 0x7a, 0xa0, 0xa2, 0xa0, 0xac, + 0xb6, 0xb7, 0xb1, 0xa0, 0x93, 0x97, 0x95, 0x82, 0x72, 0x68, 0x64, + 0x69, 0x6e, 0x68, 0x6b, 0x7c, 0x89, 0x90, 0x96, 0x93, 0x95, 0xa1, + 0x9f, 0x91, 0x89, 0x84, 0x80, 0x7b, 0x73, 0x71, 0x76, 0x7a, 0x7a, + 0x7c, 0x81, 0x83, 0x83, 0x83, 0x83, 0x84, 0x84, 0x7e, 0x77, 0x74, + 0x6f, 0x6c, 0x66, 0x60, 0x59, 0x57, 0x53, 0x4b, 0x4c, 0x4a, 0x4e, + 0x54, 0x73, 0xa7, 0xb1, 0xaa, 0xb7, 0xc1, 0xbc, 0xb7, 0x9f, 0x83, + 0x7b, 0x80, 0x6c, 0x56, 0x58, 0x60, 0x70, 0x83, 0x87, 0x88, 0xa0, + 0xb3, 0xad, 0xa3, 0x98, 0x88, 0x83, 0x7c, 0x68, 0x5c, 0x60, 0x68, + 0x6e, 0x75, 0x79, 0x83, 0x98, 0xa3, 0x9f, 0x96, 0x91, 0x8b, 0x85, + 0x7c, 0x74, 0x76, 0x7c, 0x7d, 0x7e, 0x81, 0x7d, 0x7a, 0x7b, 0x78, + 0x74, 0x70, 0x6c, 0x67, 0x63, 0x5f, 0x59, 0x55, 0x51, 0x58, 0x5e, + 0x70, 0xa2, 0xbd, 0xb4, 0xaa, 0xb3, 0xb1, 0xa3, 0x8f, 0x6e, 0x63, + 0x6c, 0x69, 0x5f, 0x66, 0x75, 0x8b, 0xa2, 0xa5, 0x9c, 0xa1, 0xa7, + 0x9d, 0x8a, 0x78, 0x6b, 0x6d, 0x70, 0x6c, 0x6a, 0x74, 0x82, 0x8a, + 0x8b, 0x85, 0x85, 0x8c, 0x8f, 0x87, 0x80, 0x81, 0x84, 0x85, 0x83, + 0x82, 0x83, 0x85, 0x82, 0x7e, 0x7b, 0x79, 0x78, 0x78, 0x77, 0x76, + 0x74, 0x71, 0x6c, 0x67, 0x61, 0x5b, 0x59, 0x56, 0x54, 0x5b, 0x6a, + 0x7f, 0x9c, 0xb8, 0xbe, 0xb3, 0xa4, 0x9c, 0x8c, 0x78, 0x67, 0x5b, + 0x5c, 0x6c, 0x7f, 0x88, 0x8f, 0x9b, 0xa8, 0xab, 0xa3, 0x93, 0x83, + 0x78, 0x73, 0x6c, 0x64, 0x66, 0x72, 0x84, 0x8f, 0x93, 0x91, 0x90, + 0x91, 0x8c, 0x81, 0x74, 0x70, 0x73, 0x78, 0x79, 0x7c, 0x85, 0x8d, + 0x8f, 0x8d, 0x8c, 0x8a, 0x86, 0x80, 0x7a, 0x77, 0x76, 0x76, 0x76, + 0x77, 0x77, 0x76, 0x73, 0x70, 0x6b, 0x65, 0x5e, 0x5a, 0x59, 0x57, + 0x5a, 0x66, 0x74, 0x85, 0xa7, 0xc1, 0xbc, 0xa8, 0x99, 0x8e, 0x7f, + 0x72, 0x64, 0x5c, 0x68, 0x80, 0x90, 0x95, 0x99, 0x9f, 0xa1, 0x9c, + 0x8c, 0x79, 0x6c, 0x6b, 0x70, 0x74, 0x7a, 0x83, 0x8e, 0x99, 0x9a, + 0x91, 0x83, 0x7b, 0x75, 0x6e, 0x6a, 0x69, 0x6e, 0x7c, 0x8e, 0x98, + 0x98, 0x96, 0x93, 0x8a, 0x81, 0x7b, 0x78, 0x7a, 0x7f, 0x81, 0x80, + 0x7d, 0x7b, 0x78, 0x77, 0x75, 0x73, 0x71, 0x71, 0x70, 0x6d, 0x68, + 0x65, 0x66, 0x68, 0x68, 0x66, 0x64, 0x6a, 0x76, 0x84, 0x9e, 0xba, + 0xbf, 0xab, 0x95, 0x84, 0x75, 0x6c, 0x69, 0x6d, 0x76, 0x87, 0x97, + 0x9e, 0x9f, 0x9c, 0x95, 0x8d, 0x84, 0x78, 0x6c, 0x6b, 0x72, 0x7a, + 0x80, 0x87, 0x8d, 0x91, 0x92, 0x8d, 0x83, 0x78, 0x70, 0x6d, 0x6e, + 0x73, 0x7b, 0x84, 0x8d, 0x94, 0x94, 0x8f, 0x88, 0x83, 0x81, 0x82, + 0x84, 0x84, 0x85, 0x83, 0x7f, 0x7a, 0x76, 0x74, 0x75, 0x77, 0x77, + 0x76, 0x74, 0x73, 0x72, 0x70, 0x6e, 0x6e, 0x6d, 0x69, 0x65, 0x65, + 0x68, 0x69, 0x67, 0x6e, 0x82, 0x93, 0xa2, 0xac, 0xab, 0xa1, 0x95, + 0x88, 0x7a, 0x71, 0x71, 0x78, 0x80, 0x85, 0x8a, 0x91, 0x96, 0x98, + 0x95, 0x8d, 0x85, 0x7f, 0x7a, 0x75, 0x74, 0x78, 0x81, 0x88, 0x8b, + 0x89, 0x88, 0x86, 0x7f, 0x74, 0x6d, 0x6c, 0x71, 0x7a, 0x81, 0x85, + 0x86, 0x8c, 0x94, 0x94, 0x8d, 0x86, 0x82, 0x80, 0x80, 0x80, 0x7e, + 0x7c, 0x7d, 0x7f, 0x7e, 0x7d, 0x7b, 0x7a, 0x78, 0x76, 0x73, 0x71, + 0x6e, 0x6c, 0x6d, 0x6f, 0x6f, 0x6f, 0x71, 0x72, 0x71, 0x70, 0x6e, + 0x69, 0x67, 0x70, 0x7f, 0x96, 0xac, 0xb2, 0xa8, 0x9c, 0x93, 0x89, + 0x81, 0x79, 0x73, 0x75, 0x80, 0x8d, 0x95, 0x96, 0x94, 0x91, 0x8d, + 0x87, 0x7e, 0x74, 0x6f, 0x73, 0x7a, 0x80, 0x85, 0x88, 0x87, 0x86, + 0x84, 0x81, 0x7c, 0x77, 0x75, 0x74, 0x75, 0x79, 0x7e, 0x82, 0x88, + 0x91, 0x96, 0x92, 0x8b, 0x85, 0x81, 0x7e, 0x7d, 0x7f, 0x81, 0x83, + 0x85, 0x85, 0x80, 0x7c, 0x7b, 0x7b, 0x78, 0x76, 0x74, 0x72, 0x72, + 0x74, 0x75, 0x74, 0x74, 0x75, 0x72, 0x6d, 0x6d, 0x6f, 0x6d, 0x6b, + 0x70, 0x75, 0x76, 0x78, 0x78, 0x73, 0x6d, 0x6d, 0x70, 0x7b, 0x8d, + 0x94, 0x91, 0x8e, 0x8d, 0x83, 0x7a, 0x79, 0x70, 0x6a, 0x7e, 0x9c, + 0xa8, 0xa4, 0xa2, 0x9e, 0x94, 0x8f, 0x8c, 0x7f, 0x6f, 0x70, 0x7a, + 0x7f, 0x83, 0x8a, 0x8e, 0x8c, 0x90, 0x94, 0x8f, 0x83, 0x7e, 0x7d, + 0x77, 0x74, 0x77, 0x7a, 0x7a, 0x7e, 0x84, 0x84, 0x82, 0x83, 0x85, + 0x83, 0x80, 0x7f, 0x7b, 0x77, 0x77, 0x7c, 0x82, 0x86, 0x8a, 0x8c, + 0x8b, 0x89, 0x89, 0x89, 0x86, 0x81, 0x7c, 0x79, 0x79, 0x7a, 0x7b, + 0x7b, 0x7c, 0x7b, 0x7a, 0x79, 0x78, 0x76, 0x75, 0x73, 0x72, 0x72, + 0x72, 0x73, 0x74, 0x75, 0x75, 0x76, 0x78, 0x7a, 0x7b, 0x7b, 0x7d, + 0x7d, 0x7c, 0x7b, 0x7d, 0x7d, 0x7c, 0x7b, 0x7b, 0x7c, 0x7b, 0x7a, + 0x79, 0x77, 0x75, 0x7a, 0x86, 0x8d, 0x8e, 0x8e, 0x91, 0x91, 0x8e, + 0x8d, 0x8b, 0x88, 0x85, 0x87, 0x89, 0x88, 0x87, 0x87, 0x86, 0x84, + 0x84, 0x84, 0x82, 0x80, 0x80, 0x80, 0x80, 0x81, 0x81, 0x7f, 0x7d, + 0x7d, 0x7d, 0x7d, 0x7e, 0x7e, 0x7e, 0x7d, 0x7c, 0x7c, 0x7c, 0x7d, + 0x7c, 0x7c, 0x7d, 0x7e, 0x80, 0x82, 0x84, 0x83, 0x80, 0x7e, 0x7c, + 0x7d, 0x7e, 0x81, 0x83, 0x85, 0x86, 0x86, 0x85, 0x83, 0x81, 0x7f, + 0x7e, 0x7c, 0x7b, 0x7a, 0x7a, 0x7a, 0x7b, 0x7b, 0x7a, 0x7a, 0x7b, + 0x7b, 0x7b, 0x7b, 0x7b, 0x7a, 0x7a, 0x7a, 0x7c, 0x7d, 0x7e, 0x7e, + 0x7d, 0x7c, 0x7d, 0x7f, 0x80, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x82, 0x82, 0x82, 0x82, 0x84, 0x85, 0x86, 0x86, 0x85, 0x84, 0x85, + 0x85, 0x85, 0x83, 0x83, 0x83, 0x83, 0x84, 0x84, 0x83, 0x81, 0x80, + 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, + 0x7e, 0x7e, 0x7e, 0x7d, 0x7c, 0x7d, 0x7e, 0x7d, 0x7d, 0x7d, 0x7d, + 0x7e, 0x7f, 0x80, 0x81, 0x81, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7e, + 0x7e, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7e, 0x7e, 0x7d, + 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7d, 0x7e, 0x7e, 0x7f, 0x7e, 0x7e, + 0x7f, 0x80, 0x7f, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, 0x7e, + 0x7e, 0x7e, 0x7d, 0x7d, 0x7e, 0x7d, 0x7c, 0x7c, 0x7d, 0x7d, 0x7c, + 0x7c, 0x7c, 0x7b, 0x7c, 0x7d, 0x7f, 0x80, 0x82, 0x84, 0x87, 0x89, + 0x88, 0x87, 0x88, 0x8a, 0x8b, 0x8a, 0x88, 0x85, 0x85, 0x86, 0x85, + 0x84, 0x82, 0x81, 0x81, 0x81, 0x80, 0x7e, 0x7d, 0x7e, 0x7f, 0x80, + 0x82, 0x81, 0x7e, 0x7e, 0x7e, 0x7e, 0x7d, 0x7d, 0x7c, 0x7c, 0x7d, + 0x7b, 0x7c, 0x7e, 0x80, 0x80, 0x7f, 0x80, 0x82, 0x83, 0x84, 0x83, + 0x80, 0x7e, 0x80, 0x7f, 0x7b, 0x79, 0x78, 0x78, 0x79, 0x79, 0x79, + 0x77, 0x74, 0x77, 0x78, 0x77, 0x77, 0x77, 0x76, 0x73, 0x73, 0x72, + 0x6f, 0x6f, 0x6e, 0x6e, 0x6f, 0x70, 0x70, 0x72, 0x70, 0x6d, 0x6a, + 0x69, 0x67, 0x6d, 0x7e, 0x80, 0x83, 0x9a, 0xab, 0xaa, 0xa3, 0xa2, + 0x9a, 0x95, 0x94, 0x8c, 0x7e, 0x78, 0x7c, 0x7c, 0x7f, 0x84, 0x86, + 0x86, 0x8c, 0x93, 0x8f, 0x89, 0x86, 0x84, 0x80, 0x7f, 0x7b, 0x72, + 0x73, 0x77, 0x79, 0x79, 0x7b, 0x7c, 0x7e, 0x84, 0x85, 0x82, 0x80, + 0x82, 0x82, 0x80, 0x7e, 0x7b, 0x7f, 0x85, 0x84, 0x81, 0x84, 0x8a, + 0x8b, 0x8a, 0x88, 0x85, 0x87, 0x89, 0x86, 0x81, 0x7e, 0x7e, 0x7d, + 0x7c, 0x78, 0x75, 0x76, 0x76, 0x70, 0x6c, 0x6e, 0x71, 0x74, 0x73, + 0x71, 0x71, 0x74, 0x74, 0x73, 0x72, 0x72, 0x71, 0x6e, 0x6b, 0x69, + 0x6b, 0x6b, 0x68, 0x67, 0x69, 0x6a, 0x67, 0x64, 0x62, 0x61, 0x72, + 0x96, 0xab, 0xac, 0xaa, 0xaf, 0xaf, 0xaa, 0x9e, 0x8d, 0x85, 0x86, + 0x88, 0x82, 0x7f, 0x82, 0x88, 0x90, 0x91, 0x8f, 0x8c, 0x8d, 0x8c, + 0x87, 0x81, 0x7d, 0x7c, 0x7b, 0x7b, 0x76, 0x75, 0x77, 0x78, 0x77, + 0x76, 0x76, 0x79, 0x7d, 0x7e, 0x80, 0x82, 0x85, 0x87, 0x86, 0x84, + 0x81, 0x81, 0x84, 0x86, 0x82, 0x80, 0x83, 0x85, 0x85, 0x82, 0x82, + 0x85, 0x88, 0x88, 0x84, 0x81, 0x81, 0x7e, 0x7a, 0x77, 0x73, 0x72, + 0x74, 0x73, 0x6f, 0x6d, 0x6e, 0x70, 0x72, 0x73, 0x72, 0x74, 0x76, + 0x75, 0x73, 0x72, 0x73, 0x72, 0x72, 0x70, 0x6f, 0x70, 0x71, 0x6f, + 0x6e, 0x70, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x75, 0x78, 0x79, 0x80, + 0x8a, 0x94, 0xa3, 0xab, 0xa9, 0xa4, 0xa3, 0x9f, 0x98, 0x93, 0x8e, + 0x8d, 0x8e, 0x8d, 0x89, 0x89, 0x8a, 0x8a, 0x89, 0x87, 0x85, 0x82, + 0x82, 0x80, 0x7e, 0x7e, 0x7e, 0x7e, 0x7d, 0x7b, 0x79, 0x78, 0x78, + 0x78, 0x76, 0x76, 0x79, 0x7a, 0x7c, 0x7f, 0x82, 0x87, 0x8b, 0x8d, + 0x8d, 0x8d, 0x8e, 0x8e, 0x89, 0x85, 0x83, 0x81, 0x81, 0x80, 0x7c, + 0x7b, 0x7b, 0x7c, 0x7b, 0x7a, 0x78, 0x76, 0x75, 0x73, 0x70, 0x6e, + 0x6e, 0x6d, 0x6c, 0x6d, 0x6f, 0x71, 0x72, 0x73, 0x75, 0x76, 0x75, + 0x75, 0x78, 0x79, 0x77, 0x77, 0x77, 0x78, 0x78, 0x7a, 0x79, 0x77, + 0x79, 0x7a, 0x7b, 0x7b, 0x7c, 0x7d, 0x7e, 0x7e, 0x7a, 0x78, 0x78, + 0x7d, 0x85, 0x8c, 0x92, 0x95, 0x9b, 0xa4, 0xa4, 0xa0, 0x9f, 0xa0, + 0x9e, 0x9b, 0x97, 0x92, 0x90, 0x8f, 0x8c, 0x87, 0x85, 0x84, 0x82, + 0x81, 0x7f, 0x7e, 0x7f, 0x80, 0x7e, 0x7b, 0x7a, 0x79, 0x76, 0x75, + 0x74, 0x73, 0x73, 0x75, 0x77, 0x77, 0x79, 0x7c, 0x81, 0x84, 0x85, + 0x86, 0x89, 0x8b, 0x8c, 0x8b, 0x8a, 0x8b, 0x8b, 0x88, 0x83, 0x81, + 0x80, 0x7d, 0x7a, 0x77, 0x75, 0x76, 0x75, 0x73, 0x72, 0x72, 0x72, + 0x70, 0x6f, 0x6e, 0x6d, 0x6d, 0x6d, 0x6d, 0x6e, 0x70, 0x71, 0x72, + 0x75, 0x76, 0x77, 0x79, 0x79, 0x7a, 0x7b, 0x7c, 0x7c, 0x7d, 0x7f, + 0x7e, 0x7d, 0x7d, 0x7e, 0x7d, 0x7d, 0x7d, 0x7c, 0x7c, 0x7e, 0x7e, + 0x7b, 0x7b, 0x7e, 0x7f, 0x7f, 0x80, 0x84, 0x89, 0x90, 0x94, 0x94, + 0x99, 0x9f, 0xa1, 0x9f, 0x9f, 0xa0, 0xa1, 0xa1, 0x9d, 0x99, 0x98, + 0x94, 0x90, 0x8c, 0x88, 0x84, 0x82, 0x7f, 0x7b, 0x7a, 0x7a, 0x79, + 0x76, 0x75, 0x73, 0x71, 0x71, 0x71, 0x70, 0x71, 0x74, 0x76, 0x77, + 0x79, 0x7c, 0x7f, 0x81, 0x83, 0x85, 0x87, 0x8a, 0x89, 0x89, 0x89, + 0x8a, 0x88, 0x85, 0x82, 0x81, 0x7e, 0x7c, 0x79, 0x76, 0x74, 0x73, + 0x70, 0x6e, 0x6d, 0x6c, 0x6c, 0x6b, 0x6b, 0x6b, 0x6c, 0x6e, 0x6e, + 0x6f, 0x70, 0x73, 0x73, 0x74, 0x76, 0x78, 0x7a, 0x7b, 0x7c, 0x7d, + 0x7f, 0x80, 0x7f, 0x80, 0x81, 0x81, 0x7f, 0x81, 0x81, 0x7f, 0x7e, + 0x7f, 0x7e, 0x7d, 0x7d, 0x7c, 0x7c, 0x7b, 0x7a, 0x7a, 0x79, 0x78, + 0x79, 0x7c, 0x81, 0x85, 0x88, 0x8b, 0x92, 0x97, 0x98, 0x9a, 0x9d, + 0xa0, 0xa1, 0xa0, 0x9f, 0x9e, 0x9d, 0x9b, 0x99, 0x94, 0x90, 0x8e, + 0x8a, 0x86, 0x83, 0x80, 0x7e, 0x7c, 0x7b, 0x78, 0x76, 0x75, 0x73, + 0x72, 0x70, 0x6f, 0x6f, 0x6f, 0x6f, 0x71, 0x72, 0x73, 0x76, 0x79, + 0x7b, 0x7d, 0x7f, 0x83, 0x85, 0x86, 0x86, 0x87, 0x87, 0x86, 0x84, + 0x83, 0x82, 0x81, 0x7f, 0x7d, 0x7b, 0x79, 0x78, 0x75, 0x74, 0x73, + 0x73, 0x71, 0x71, 0x72, 0x71, 0x71, 0x72, 0x72, 0x73, 0x73, 0x74, + 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7c, 0x7c, 0x7d, + 0x7e, 0x7f, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x7e, 0x7d, 0x7d, 0x7e, + 0x7e, 0x7c, 0x7d, 0x7d, 0x7d, 0x7d, 0x7c, 0x7c, 0x81, 0x86, 0x85, + 0x87, 0x8d, 0x91, 0x93, 0x94, 0x96, 0x9a, 0x9d, 0x9d, 0x9c, 0x9c, + 0x9c, 0x9b, 0x99, 0x96, 0x92, 0x90, 0x8e, 0x8a, 0x86, 0x84, 0x82, + 0x80, 0x7e, 0x7c, 0x7a, 0x79, 0x77, 0x75, 0x75, 0x75, 0x74, 0x73, + 0x73, 0x73, 0x74, 0x75, 0x75, 0x77, 0x79, 0x7b, 0x7d, 0x7e, 0x81, + 0x83, 0x83, 0x85, 0x86, 0x86, 0x86, 0x87, 0x86, 0x84, 0x83, 0x82, + 0x81, 0x7f, 0x7d, 0x7c, 0x7a, 0x79, 0x77, 0x76, 0x76, 0x76, 0x75, + 0x75, 0x75, 0x75, 0x75, 0x75, 0x76, 0x76, 0x77, 0x77, 0x78, 0x78, + 0x7a, 0x7b, 0x7a, 0x7a, 0x7b, 0x7c, 0x7c, 0x7c, 0x7c, 0x7d, 0x7d, + 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7e, 0x7f, 0x80, 0x80, + 0x7f, 0x80, 0x80, 0x80, 0x81, 0x83, 0x84, 0x84, 0x86, 0x88, 0x89, + 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8d, 0x8e, 0x8e, 0x8e, 0x8d, 0x8d, + 0x8c, 0x8b, 0x8a, 0x89, 0x87, 0x86, 0x85, 0x84, 0x82, 0x81, 0x7f, + 0x7e, 0x7e, 0x7d, 0x7c, 0x7b, 0x7a, 0x79, 0x79, 0x79, 0x78, 0x77, + 0x78, 0x78, 0x78, 0x77, 0x78, 0x78, 0x79, 0x79, 0x79, 0x79, 0x7a, + 0x7a, 0x7a, 0x7a, 0x7a, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, + 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7b, 0x7b, 0x7b, 0x7b, + 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7d, 0x7d, 0x7e, + 0x7e, 0x7e, 0x7f, 0x7f, 0x80, 0x80, 0x81, 0x81, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x84, 0x84, 0x84, + 0x84, 0x85, 0x85, 0x86, 0x86, 0x87, 0x87, 0x88, 0x88, 0x89, 0x89, + 0x89, 0x88, 0x88, 0x87, 0x87, 0x87, 0x86, 0x85, 0x84, 0x83, 0x83, + 0x82, 0x81, 0x80, 0x80, 0x7f, 0x7e, 0x7d, 0x7d, 0x7d, 0x7c, 0x7b, + 0x7b, 0x7a, 0x7a, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, + 0x79, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7b, 0x7b, 0x7b, 0x7b, 0x7c, + 0x7c, 0x7c, 0x7d, 0x7d, 0x7d, 0x7e, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, + 0x7d, 0x7d, 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x81, 0x81, 0x80, 0x81, 0x81, 0x81, 0x81, 0x81, 0x82, 0x82, 0x81, + 0x81, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x81, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x81, 0x81, 0x82, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7d, 0x7d, + 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7e, + 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7e, 0x7e, 0x7d, 0x7d, 0x7d, + 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7e, 0x7e, + 0x7e, 0x7e, 0x7e, 0x7f, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x80, + 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, + 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, + 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x80, + 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, + 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, + 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, + }, + { // 8 + 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, + 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, + 0x80, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, + 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, + 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x80, + 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x81, + 0x81, 0x89, 0x91, 0x84, 0x81, 0x88, 0x79, 0x6b, 0x71, 0x74, 0x77, + 0x81, 0x84, 0x87, 0x87, 0x7b, 0x6f, 0x6e, 0x6a, 0x64, 0x65, 0x63, + 0x62, 0x67, 0x73, 0x71, 0x69, 0x84, 0x88, 0x70, 0x76, 0x81, 0x71, + 0x63, 0x6f, 0x6b, 0x69, 0x80, 0x91, 0x95, 0xa0, 0xa8, 0xa3, 0xa1, + 0x9c, 0x90, 0x86, 0x82, 0x79, 0x78, 0x7f, 0x81, 0x89, 0x92, 0x9c, + 0xa4, 0xa5, 0x9e, 0x96, 0x8e, 0x83, 0x79, 0x72, 0x6d, 0x6a, 0x6f, + 0x6e, 0x71, 0x7b, 0x7a, 0x7e, 0x7e, 0x7b, 0x79, 0x6e, 0x67, 0x62, + 0x66, 0x5e, 0x56, 0x51, 0x4f, 0x95, 0xa8, 0x7f, 0x9b, 0xc6, 0xa6, + 0x81, 0x93, 0x89, 0x6f, 0x69, 0x68, 0x72, 0x71, 0x6e, 0x84, 0x92, + 0x8c, 0x97, 0xa1, 0x9c, 0x91, 0x8a, 0x88, 0x80, 0x73, 0x6d, 0x74, + 0x74, 0x72, 0x7c, 0x90, 0x9a, 0x95, 0x99, 0x9b, 0x8c, 0x7f, 0x7c, + 0x74, 0x6f, 0x6c, 0x73, 0x7e, 0x7c, 0x7d, 0x83, 0x7f, 0x7b, 0x77, + 0x73, 0x70, 0x66, 0x62, 0x5f, 0x5a, 0x51, 0x74, 0xa6, 0x91, 0x90, + 0xba, 0xb9, 0x94, 0x8f, 0x99, 0x7f, 0x65, 0x65, 0x6e, 0x6c, 0x65, + 0x74, 0x91, 0x90, 0x8e, 0xa0, 0xa5, 0x93, 0x8b, 0x8b, 0x7d, 0x72, + 0x6f, 0x6f, 0x73, 0x76, 0x81, 0x90, 0x93, 0x95, 0x9d, 0x96, 0x8d, + 0x8b, 0x82, 0x76, 0x73, 0x72, 0x6e, 0x71, 0x6f, 0x6c, 0x6e, 0x6a, + 0x6a, 0x6c, 0x6a, 0x67, 0x65, 0x64, 0x5f, 0x5b, 0x58, 0x71, 0x9a, + 0x8d, 0x90, 0xb7, 0xb1, 0x95, 0x95, 0x9a, 0x82, 0x6e, 0x6a, 0x6b, + 0x68, 0x64, 0x72, 0x86, 0x8f, 0x91, 0x9e, 0xa7, 0x9b, 0x94, 0x92, + 0x84, 0x77, 0x74, 0x6e, 0x6c, 0x74, 0x7c, 0x85, 0x8c, 0x93, 0x9a, + 0x99, 0x93, 0x8d, 0x87, 0x80, 0x7b, 0x77, 0x71, 0x6f, 0x6f, 0x6a, + 0x69, 0x66, 0x63, 0x67, 0x64, 0x61, 0x62, 0x5f, 0x60, 0x5e, 0x5a, + 0x59, 0x74, 0x9f, 0x92, 0x98, 0xc1, 0xaf, 0x8e, 0x95, 0x90, 0x73, + 0x6a, 0x69, 0x6b, 0x6c, 0x69, 0x77, 0x8b, 0x8e, 0x92, 0xa7, 0xa8, + 0x97, 0x97, 0x95, 0x83, 0x7a, 0x77, 0x71, 0x70, 0x76, 0x7d, 0x87, + 0x89, 0x8b, 0x94, 0x92, 0x8e, 0x8d, 0x88, 0x81, 0x80, 0x7c, 0x6f, + 0x71, 0x73, 0x68, 0x65, 0x68, 0x63, 0x65, 0x65, 0x5f, 0x5f, 0x62, + 0x60, 0x5e, 0x5b, 0x57, 0x56, 0x82, 0xa3, 0x86, 0xa0, 0xc7, 0xa6, + 0x8d, 0x9d, 0x92, 0x72, 0x6c, 0x6f, 0x6d, 0x65, 0x6a, 0x7c, 0x85, + 0x83, 0x95, 0xa6, 0x9f, 0x9c, 0x9c, 0x94, 0x84, 0x7b, 0x78, 0x6f, + 0x6f, 0x76, 0x7c, 0x83, 0x89, 0x90, 0x98, 0x94, 0x91, 0x93, 0x87, + 0x7e, 0x81, 0x7c, 0x71, 0x73, 0x73, 0x6b, 0x69, 0x68, 0x65, 0x61, + 0x5d, 0x5e, 0x60, 0x5d, 0x5a, 0x5e, 0x5d, 0x57, 0x50, 0x68, 0x9d, + 0x92, 0x8a, 0xbe, 0xbe, 0x95, 0x9c, 0xa4, 0x84, 0x71, 0x71, 0x71, + 0x66, 0x5d, 0x6e, 0x80, 0x7e, 0x88, 0xa4, 0xa5, 0x99, 0x9c, 0xa3, + 0x93, 0x81, 0x84, 0x7a, 0x6c, 0x6d, 0x70, 0x75, 0x79, 0x80, 0x8d, + 0x96, 0x94, 0x98, 0x9a, 0x90, 0x86, 0x7e, 0x7c, 0x78, 0x71, 0x6d, + 0x6f, 0x6c, 0x68, 0x67, 0x65, 0x63, 0x61, 0x63, 0x60, 0x5c, 0x5d, + 0x61, 0x66, 0x61, 0x61, 0x69, 0x8a, 0xa0, 0x8d, 0xa3, 0xba, 0x9f, + 0x8e, 0x98, 0x90, 0x74, 0x72, 0x77, 0x6e, 0x67, 0x74, 0x7e, 0x83, + 0x8b, 0x9a, 0xa1, 0x9d, 0x9d, 0x97, 0x8e, 0x84, 0x7a, 0x75, 0x6d, + 0x69, 0x6e, 0x72, 0x7a, 0x89, 0x8e, 0x8f, 0x9c, 0x9e, 0x95, 0x95, + 0x92, 0x85, 0x7a, 0x78, 0x74, 0x6c, 0x6a, 0x68, 0x61, 0x61, 0x68, + 0x67, 0x63, 0x68, 0x6b, 0x66, 0x60, 0x64, 0x68, 0x64, 0x5b, 0x5b, + 0x5b, 0x70, 0x8d, 0x81, 0x90, 0xaf, 0xa8, 0x9c, 0xa9, 0xab, 0x93, + 0x89, 0x88, 0x7f, 0x70, 0x6b, 0x6f, 0x70, 0x6e, 0x7b, 0x89, 0x8c, + 0x92, 0x9b, 0xa1, 0x9b, 0x97, 0x97, 0x8b, 0x7f, 0x7b, 0x76, 0x6c, + 0x6a, 0x6d, 0x70, 0x75, 0x7d, 0x87, 0x8d, 0x94, 0x9d, 0x9e, 0x98, + 0x8f, 0x89, 0x81, 0x75, 0x72, 0x72, 0x6c, 0x68, 0x69, 0x6c, 0x6d, + 0x6d, 0x72, 0x73, 0x6c, 0x68, 0x66, 0x65, 0x62, 0x60, 0x61, 0x5d, + 0x56, 0x57, 0x60, 0x70, 0x76, 0x86, 0x9d, 0x9f, 0xa5, 0xb2, 0xb2, + 0xa7, 0xa5, 0x9d, 0x8e, 0x82, 0x76, 0x70, 0x69, 0x66, 0x6a, 0x73, + 0x78, 0x80, 0x8e, 0x93, 0x99, 0xa0, 0xa2, 0xa0, 0x9a, 0x95, 0x8b, + 0x7e, 0x74, 0x6d, 0x65, 0x61, 0x61, 0x63, 0x6d, 0x76, 0x7f, 0x8c, + 0x96, 0xa0, 0xa4, 0xa7, 0xa6, 0x9f, 0x98, 0x8c, 0x82, 0x7a, 0x6f, + 0x6a, 0x65, 0x62, 0x60, 0x61, 0x63, 0x63, 0x68, 0x6b, 0x6c, 0x6e, + 0x6b, 0x6c, 0x68, 0x63, 0x65, 0x66, 0x68, 0x63, 0x5f, 0x5e, 0x5f, + 0x64, 0x71, 0x82, 0x85, 0x94, 0xa6, 0xa9, 0xab, 0xb2, 0xb4, 0xaa, + 0xa5, 0x9f, 0x91, 0x85, 0x7d, 0x75, 0x6c, 0x6b, 0x6b, 0x6c, 0x70, + 0x78, 0x81, 0x87, 0x8e, 0x93, 0x95, 0x96, 0x94, 0x91, 0x8b, 0x84, + 0x7e, 0x77, 0x71, 0x6f, 0x6d, 0x6e, 0x73, 0x79, 0x80, 0x86, 0x8f, + 0x97, 0x97, 0x9c, 0x9d, 0x98, 0x93, 0x8f, 0x89, 0x7e, 0x78, 0x73, + 0x6a, 0x63, 0x62, 0x5d, 0x5a, 0x5b, 0x5b, 0x5d, 0x5f, 0x5f, 0x62, + 0x64, 0x62, 0x5f, 0x60, 0x60, 0x60, 0x63, 0x64, 0x61, 0x60, 0x66, + 0x66, 0x6e, 0x80, 0x81, 0x8a, 0x9b, 0x9f, 0xa2, 0xab, 0xb4, 0xad, + 0xad, 0xae, 0xa2, 0x9a, 0x93, 0x89, 0x7d, 0x77, 0x73, 0x6d, 0x6b, + 0x6d, 0x72, 0x73, 0x7a, 0x80, 0x84, 0x8b, 0x8e, 0x92, 0x92, 0x91, + 0x8f, 0x8c, 0x86, 0x81, 0x7f, 0x7a, 0x79, 0x7b, 0x77, 0x7b, 0x80, + 0x7f, 0x84, 0x89, 0x88, 0x89, 0x8c, 0x89, 0x87, 0x86, 0x82, 0x7d, + 0x79, 0x75, 0x70, 0x6a, 0x67, 0x61, 0x5d, 0x5b, 0x57, 0x56, 0x57, + 0x5a, 0x63, 0x68, 0x67, 0x66, 0x60, 0x5c, 0x5a, 0x56, 0x56, 0x55, + 0x51, 0x54, 0x57, 0x5a, 0x65, 0x75, 0x79, 0x84, 0x9a, 0x9c, 0xa1, + 0xb2, 0xb5, 0xb3, 0xb8, 0xba, 0xb0, 0xa9, 0xa7, 0x99, 0x8e, 0x88, + 0x7e, 0x75, 0x70, 0x6f, 0x69, 0x69, 0x6d, 0x6d, 0x71, 0x76, 0x7b, + 0x7f, 0x83, 0x88, 0x89, 0x8b, 0x8c, 0x8d, 0x8b, 0x8b, 0x8b, 0x86, + 0x89, 0x88, 0x82, 0x85, 0x85, 0x81, 0x82, 0x82, 0x7f, 0x7e, 0x7e, + 0x7b, 0x78, 0x77, 0x73, 0x71, 0x6e, 0x6b, 0x6a, 0x69, 0x6a, 0x6d, + 0x6f, 0x6f, 0x73, 0x74, 0x74, 0x76, 0x75, 0x73, 0x71, 0x6e, 0x6c, + 0x69, 0x67, 0x65, 0x63, 0x5f, 0x5e, 0x5e, 0x5b, 0x59, 0x5b, 0x65, + 0x65, 0x66, 0x7a, 0x7f, 0x7e, 0x90, 0x99, 0x98, 0xa3, 0xad, 0xab, + 0xac, 0xb2, 0xac, 0xa7, 0xa5, 0x9e, 0x95, 0x8e, 0x89, 0x80, 0x7a, + 0x78, 0x72, 0x6f, 0x70, 0x70, 0x70, 0x73, 0x77, 0x79, 0x7b, 0x7f, + 0x82, 0x83, 0x85, 0x87, 0x88, 0x8a, 0x8b, 0x8a, 0x8c, 0x8b, 0x89, + 0x8a, 0x89, 0x86, 0x85, 0x84, 0x80, 0x7e, 0x7d, 0x79, 0x77, 0x75, + 0x73, 0x72, 0x71, 0x72, 0x71, 0x71, 0x76, 0x78, 0x7a, 0x7f, 0x82, + 0x83, 0x86, 0x88, 0x87, 0x86, 0x86, 0x83, 0x81, 0x80, 0x7d, 0x7a, + 0x79, 0x76, 0x74, 0x72, 0x71, 0x6f, 0x6d, 0x6d, 0x6b, 0x68, 0x6a, + 0x68, 0x66, 0x67, 0x66, 0x64, 0x68, 0x71, 0x6c, 0x71, 0x7f, 0x7a, + 0x80, 0x8d, 0x8a, 0x90, 0x97, 0x99, 0x9b, 0x9d, 0x9f, 0x9c, 0x9b, + 0x9a, 0x98, 0x92, 0x8e, 0x8d, 0x86, 0x83, 0x83, 0x7c, 0x7c, 0x7c, + 0x78, 0x78, 0x7a, 0x7a, 0x79, 0x7b, 0x7c, 0x7c, 0x7c, 0x7e, 0x7f, + 0x7e, 0x80, 0x81, 0x81, 0x83, 0x84, 0x84, 0x85, 0x84, 0x86, 0x84, + 0x84, 0x85, 0x82, 0x82, 0x81, 0x7e, 0x7e, 0x7c, 0x7b, 0x79, 0x76, + 0x77, 0x76, 0x74, 0x76, 0x74, 0x73, 0x75, 0x74, 0x74, 0x76, 0x76, + 0x77, 0x78, 0x7a, 0x7c, 0x7d, 0x7e, 0x80, 0x81, 0x82, 0x83, 0x84, + 0x84, 0x85, 0x86, 0x85, 0x85, 0x85, 0x85, 0x84, 0x83, 0x82, 0x81, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x81, 0x81, 0x81, 0x82, 0x82, 0x81, + 0x82, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, + 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x7f, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7e, 0x81, 0x7c, 0x8b, + 0x86, 0x7a, 0x85, 0x7f, 0x88, 0x7c, 0x77, 0x87, 0x83, 0x89, 0x8a, + 0x84, 0x82, 0x79, 0x81, 0x8b, 0x86, 0x82, 0x7e, 0x7e, 0x7c, 0x75, + 0x79, 0x7c, 0x7e, 0x7b, 0x78, 0x7e, 0x7d, 0x80, 0x7e, 0x7d, 0x7f, + 0x7e, 0x7d, 0x7d, 0x82, 0x81, 0x80, 0x7c, 0x81, 0x81, 0x7e, 0x7c, + 0x80, 0x85, 0x7f, 0x80, 0x82, 0x85, 0x81, 0x7d, 0x83, 0x83, 0x83, + 0x7e, 0x7f, 0x82, 0x81, 0x7e, 0x7d, 0x82, 0x80, 0x7d, 0x7d, 0x81, + 0x81, 0x7f, 0x7d, 0x81, 0x84, 0x7f, 0x7f, 0x83, 0x82, 0x80, 0x7f, + 0x7f, 0x81, 0x7f, 0x7d, 0x82, 0x82, 0x7b, 0x7d, 0x80, 0x7d, 0x7d, + 0x7f, 0x82, 0x81, 0x80, 0x7e, 0x80, 0x7f, 0x7c, 0x7e, 0x80, 0x82, + 0x82, 0x81, 0x81, 0x80, 0x7f, 0x7d, 0x7e, 0x80, 0x80, 0x7f, 0x7f, + 0x80, 0x7f, 0x7f, 0x7e, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x81, + 0x80, 0x7f, 0x80, 0x80, 0x7e, 0x7f, 0x80, 0x80, 0x80, 0x81, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x7f, + 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x81, 0x81, + 0x80, 0x80, 0x81, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, + 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x81, 0x80, 0x80, 0x80, 0x81, + 0x81, 0x80, 0x80, 0x80, 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x80, + 0x80, 0x81, 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, 0x7f, 0x7e, 0x7e, 0x7f, + 0x80, 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x80, + 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x80, + 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x7f, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, + 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x80, + 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, + 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, + 0x80, 0x80, 0x7f, + }, + { // 9 + 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, + 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, + 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7e, 0x7c, 0x7a, + 0x79, 0x7a, 0x7b, 0x7e, 0x80, 0x83, 0x86, 0x8a, 0x8e, 0x91, 0x95, + 0x98, 0x9a, 0x9c, 0x9e, 0x9f, 0x9f, 0x9e, 0x9c, 0x9b, 0x99, 0x96, + 0x93, 0x91, 0x8e, 0x8a, 0x88, 0x86, 0x83, 0x82, 0x80, 0x7f, 0x7e, + 0x7e, 0x7d, 0x7d, 0x7d, 0x7e, 0x7e, 0x7f, 0x81, 0x81, 0x81, 0x82, + 0x81, 0x81, 0x80, 0x7f, 0x7d, 0x7b, 0x79, 0x76, 0x74, 0x71, 0x6e, + 0x6b, 0x69, 0x67, 0x65, 0x64, 0x63, 0x62, 0x62, 0x62, 0x62, 0x62, + 0x64, 0x64, 0x64, 0x66, 0x67, 0x67, 0x68, 0x6a, 0x6e, 0x71, 0x75, + 0x7a, 0x7f, 0x84, 0x8a, 0x8f, 0x94, 0x99, 0x9e, 0xa1, 0xa4, 0xa6, + 0xa6, 0xa7, 0xa7, 0xa6, 0xa4, 0xa2, 0x9e, 0x99, 0x96, 0x91, 0x8d, + 0x89, 0x85, 0x81, 0x7e, 0x7d, 0x7b, 0x78, 0x78, 0x78, 0x78, 0x78, + 0x79, 0x7a, 0x7b, 0x7e, 0x80, 0x82, 0x85, 0x86, 0x87, 0x89, 0x88, + 0x87, 0x86, 0x84, 0x80, 0x7d, 0x7a, 0x76, 0x73, 0x6f, 0x6b, 0x69, + 0x66, 0x62, 0x5f, 0x5d, 0x5b, 0x59, 0x58, 0x58, 0x58, 0x59, 0x5b, + 0x5d, 0x5e, 0x5f, 0x62, 0x64, 0x66, 0x6b, 0x73, 0x79, 0x80, 0x8c, + 0x95, 0x97, 0x9e, 0xa8, 0xab, 0xab, 0xaf, 0xaf, 0xac, 0xad, 0xac, + 0xa6, 0xa4, 0xa3, 0x9c, 0x97, 0x95, 0x90, 0x88, 0x86, 0x83, 0x7d, + 0x7b, 0x7a, 0x77, 0x75, 0x76, 0x75, 0x74, 0x77, 0x77, 0x78, 0x7b, + 0x7d, 0x7d, 0x80, 0x83, 0x84, 0x85, 0x88, 0x88, 0x87, 0x88, 0x87, + 0x85, 0x84, 0x81, 0x7d, 0x7a, 0x76, 0x72, 0x6f, 0x6b, 0x66, 0x63, + 0x61, 0x5e, 0x5c, 0x5c, 0x5b, 0x5b, 0x5c, 0x5e, 0x5e, 0x61, 0x63, + 0x65, 0x67, 0x6c, 0x75, 0x79, 0x7d, 0x87, 0x8f, 0x93, 0x9a, 0xa4, + 0xa8, 0xad, 0xb2, 0xb3, 0xb3, 0xb4, 0xb3, 0xaf, 0xac, 0xa9, 0xa3, + 0x9d, 0x98, 0x91, 0x8b, 0x87, 0x83, 0x7d, 0x78, 0x75, 0x71, 0x70, + 0x6f, 0x6d, 0x6d, 0x70, 0x74, 0x76, 0x79, 0x7c, 0x7d, 0x80, 0x83, + 0x85, 0x85, 0x87, 0x8c, 0x8f, 0x91, 0x8c, 0x84, 0x7d, 0x77, 0x74, + 0x6b, 0x63, 0x60, 0x5b, 0x55, 0x4f, 0x4d, 0x4c, 0x4d, 0x4b, 0x4b, + 0x4b, 0x49, 0x48, 0x47, 0x53, 0x73, 0x8f, 0x97, 0x99, 0x9f, 0xa8, + 0xaa, 0xa1, 0x93, 0x8e, 0x95, 0x9c, 0x99, 0x8f, 0x8b, 0x93, 0x9c, + 0x98, 0x8b, 0x86, 0x8a, 0x8d, 0x8a, 0x84, 0x82, 0x86, 0x88, 0x85, + 0x7d, 0x78, 0x7d, 0x82, 0x80, 0x7c, 0x82, 0x8b, 0x8a, 0x88, 0x88, + 0x88, 0x8a, 0x8a, 0x86, 0x86, 0x88, 0x86, 0x82, 0x7a, 0x75, 0x72, + 0x6b, 0x63, 0x61, 0x5f, 0x5f, 0x5f, 0x5c, 0x58, 0x55, 0x50, 0x52, + 0x55, 0x4f, 0x51, 0x55, 0x4f, 0x44, 0x5c, 0x9c, 0xbb, 0xb0, 0x99, + 0x8d, 0x96, 0x9a, 0x88, 0x73, 0x7c, 0x95, 0x9e, 0x97, 0x90, 0x8f, + 0x98, 0x9e, 0x95, 0x89, 0x85, 0x87, 0x87, 0x84, 0x81, 0x83, 0x86, + 0x87, 0x84, 0x7f, 0x7d, 0x7f, 0x80, 0x7f, 0x81, 0x85, 0x86, 0x87, + 0x89, 0x8b, 0x8c, 0x8c, 0x88, 0x85, 0x83, 0x84, 0x82, 0x7c, 0x76, + 0x75, 0x73, 0x6d, 0x65, 0x63, 0x65, 0x63, 0x5d, 0x5b, 0x5a, 0x57, + 0x57, 0x56, 0x53, 0x54, 0x4f, 0x4d, 0x48, 0x57, 0x98, 0xc3, 0xb7, + 0x94, 0x81, 0x85, 0x8c, 0x81, 0x6c, 0x74, 0x95, 0xa4, 0x9e, 0x90, + 0x86, 0x8c, 0x94, 0x8a, 0x7d, 0x7b, 0x80, 0x89, 0x8d, 0x88, 0x83, + 0x84, 0x89, 0x87, 0x80, 0x79, 0x79, 0x80, 0x83, 0x81, 0x84, 0x85, + 0x86, 0x89, 0x8b, 0x89, 0x85, 0x83, 0x82, 0x80, 0x7d, 0x7c, 0x7c, + 0x7a, 0x78, 0x75, 0x71, 0x6f, 0x6e, 0x6c, 0x67, 0x63, 0x61, 0x5f, + 0x5e, 0x5e, 0x5c, 0x5a, 0x5c, 0x5d, 0x6a, 0x88, 0xa7, 0xb4, 0xa5, + 0x8c, 0x77, 0x70, 0x75, 0x7e, 0x88, 0x91, 0x95, 0x94, 0x8e, 0x8c, + 0x8a, 0x84, 0x81, 0x84, 0x88, 0x89, 0x86, 0x86, 0x88, 0x8a, 0x8b, + 0x86, 0x80, 0x7d, 0x7d, 0x80, 0x83, 0x80, 0x80, 0x84, 0x82, 0x7f, + 0x82, 0x87, 0x8a, 0x89, 0x84, 0x7e, 0x7a, 0x78, 0x79, 0x7b, 0x7c, + 0x77, 0x73, 0x74, 0x72, 0x6e, 0x68, 0x64, 0x66, 0x67, 0x66, 0x65, + 0x65, 0x62, 0x5d, 0x60, 0x7d, 0xab, 0xbe, 0xaa, 0x86, 0x68, 0x5f, + 0x6f, 0x86, 0x90, 0x8d, 0x89, 0x8c, 0x95, 0x98, 0x8f, 0x82, 0x7c, + 0x7e, 0x84, 0x86, 0x86, 0x87, 0x87, 0x85, 0x84, 0x84, 0x84, 0x82, + 0x82, 0x84, 0x83, 0x82, 0x85, 0x84, 0x83, 0x86, 0x86, 0x85, 0x86, + 0x86, 0x7f, 0x79, 0x76, 0x77, 0x7e, 0x81, 0x7a, 0x6e, 0x66, 0x69, + 0x72, 0x74, 0x6c, 0x63, 0x61, 0x60, 0x5e, 0x5f, 0x5c, 0x5f, 0x7e, + 0xaa, 0xbe, 0xae, 0x8a, 0x66, 0x5a, 0x6a, 0x81, 0x8f, 0x93, 0x8d, + 0x87, 0x89, 0x8e, 0x90, 0x8c, 0x84, 0x7c, 0x7e, 0x86, 0x89, 0x88, + 0x86, 0x85, 0x87, 0x88, 0x85, 0x80, 0x7f, 0x80, 0x83, 0x86, 0x85, + 0x85, 0x87, 0x88, 0x87, 0x85, 0x84, 0x82, 0x7e, 0x79, 0x78, 0x7a, + 0x7a, 0x78, 0x75, 0x73, 0x6f, 0x6d, 0x6b, 0x68, 0x66, 0x64, 0x62, + 0x5f, 0x5a, 0x58, 0x65, 0x88, 0xaf, 0xbe, 0xaa, 0x81, 0x5e, 0x56, + 0x6a, 0x88, 0x99, 0x95, 0x88, 0x81, 0x85, 0x8e, 0x92, 0x8c, 0x82, + 0x7e, 0x80, 0x82, 0x82, 0x82, 0x84, 0x87, 0x8a, 0x8b, 0x8a, 0x8a, + 0x87, 0x81, 0x7b, 0x79, 0x7c, 0x82, 0x8a, 0x8e, 0x8e, 0x8b, 0x85, + 0x7d, 0x77, 0x75, 0x77, 0x7b, 0x7c, 0x78, 0x73, 0x6f, 0x6c, 0x6c, + 0x6e, 0x6c, 0x67, 0x66, 0x62, 0x5a, 0x54, 0x59, 0x77, 0xa8, 0xc4, + 0xb8, 0x94, 0x68, 0x50, 0x59, 0x79, 0x97, 0xa0, 0x92, 0x80, 0x7a, + 0x84, 0x93, 0x96, 0x8c, 0x7f, 0x7b, 0x7c, 0x80, 0x83, 0x85, 0x87, + 0x8a, 0x8c, 0x8c, 0x8b, 0x88, 0x81, 0x7a, 0x78, 0x7b, 0x80, 0x89, + 0x8f, 0x8f, 0x8a, 0x85, 0x81, 0x7e, 0x79, 0x78, 0x79, 0x78, 0x76, + 0x75, 0x73, 0x71, 0x6e, 0x68, 0x65, 0x64, 0x61, 0x61, 0x5e, 0x56, + 0x50, 0x5c, 0x89, 0xb9, 0xc7, 0xb1, 0x81, 0x57, 0x4f, 0x68, 0x8c, + 0xa2, 0x9a, 0x83, 0x79, 0x7e, 0x8b, 0x94, 0x93, 0x89, 0x81, 0x7d, + 0x7d, 0x80, 0x82, 0x82, 0x85, 0x89, 0x8c, 0x8d, 0x8c, 0x86, 0x7f, + 0x7c, 0x7c, 0x7d, 0x7f, 0x86, 0x8b, 0x8d, 0x8c, 0x86, 0x7f, 0x7a, + 0x78, 0x78, 0x7b, 0x7c, 0x79, 0x74, 0x71, 0x6f, 0x6d, 0x6b, 0x68, + 0x66, 0x64, 0x64, 0x64, 0x5d, 0x54, 0x53, 0x68, 0x9a, 0xc0, 0xc0, + 0xa0, 0x6e, 0x4f, 0x56, 0x76, 0x98, 0xa6, 0x96, 0x7f, 0x79, 0x80, + 0x8c, 0x93, 0x8f, 0x87, 0x82, 0x7e, 0x7d, 0x80, 0x82, 0x84, 0x87, + 0x88, 0x89, 0x89, 0x87, 0x81, 0x7b, 0x7b, 0x7f, 0x86, 0x8b, 0x8c, + 0x89, 0x84, 0x80, 0x7d, 0x7b, 0x7a, 0x7c, 0x7d, 0x7c, 0x78, 0x74, + 0x71, 0x6f, 0x70, 0x70, 0x6e, 0x6a, 0x68, 0x6b, 0x6e, 0x6a, 0x64, + 0x5e, 0x57, 0x5b, 0x78, 0xa2, 0xb9, 0xb0, 0x8f, 0x69, 0x5a, 0x64, + 0x7e, 0x96, 0x9d, 0x90, 0x7f, 0x7e, 0x88, 0x90, 0x90, 0x8a, 0x84, + 0x81, 0x82, 0x84, 0x83, 0x81, 0x83, 0x87, 0x8a, 0x89, 0x85, 0x7f, + 0x7b, 0x7c, 0x7d, 0x81, 0x88, 0x8b, 0x8c, 0x8c, 0x87, 0x83, 0x81, + 0x7f, 0x7c, 0x79, 0x77, 0x7a, 0x7e, 0x7b, 0x76, 0x75, 0x75, 0x73, + 0x70, 0x6a, 0x62, 0x62, 0x67, 0x6b, 0x69, 0x61, 0x5d, 0x5e, 0x60, + 0x66, 0x6f, 0x82, 0xa1, 0xae, 0xa2, 0x87, 0x6b, 0x63, 0x72, 0x8a, + 0x9a, 0x9b, 0x8e, 0x85, 0x85, 0x89, 0x8b, 0x88, 0x81, 0x7e, 0x7e, + 0x83, 0x88, 0x87, 0x84, 0x84, 0x86, 0x88, 0x86, 0x80, 0x7a, 0x76, + 0x75, 0x79, 0x81, 0x8b, 0x92, 0x95, 0x91, 0x89, 0x82, 0x7f, 0x80, + 0x84, 0x86, 0x83, 0x7f, 0x7c, 0x79, 0x77, 0x78, 0x78, 0x75, 0x72, + 0x6e, 0x6b, 0x69, 0x6a, 0x69, 0x66, 0x65, 0x64, 0x67, 0x69, 0x66, + 0x63, 0x5f, 0x5d, 0x5c, 0x5e, 0x83, 0xaf, 0xb7, 0xa9, 0x89, 0x67, + 0x62, 0x75, 0x8d, 0xa1, 0x9d, 0x8a, 0x82, 0x84, 0x87, 0x8d, 0x8c, + 0x88, 0x88, 0x86, 0x82, 0x81, 0x7f, 0x80, 0x83, 0x82, 0x80, 0x81, + 0x80, 0x81, 0x81, 0x80, 0x7c, 0x79, 0x7c, 0x85, 0x8d, 0x90, 0x8e, + 0x89, 0x82, 0x7e, 0x7f, 0x82, 0x85, 0x87, 0x85, 0x80, 0x80, 0x7f, + 0x7b, 0x76, 0x74, 0x76, 0x78, 0x78, 0x73, 0x6d, 0x69, 0x68, 0x6a, + 0x6c, 0x6d, 0x69, 0x64, 0x65, 0x67, 0x6d, 0x69, 0x65, 0x61, 0x5d, + 0x5e, 0x63, 0x92, 0xbf, 0xbf, 0xaf, 0x89, 0x63, 0x5d, 0x74, 0x90, + 0xa5, 0x9f, 0x8b, 0x83, 0x83, 0x8b, 0x92, 0x8e, 0x84, 0x80, 0x7e, + 0x84, 0x8b, 0x86, 0x7f, 0x7e, 0x81, 0x85, 0x89, 0x83, 0x7a, 0x74, + 0x6f, 0x71, 0x77, 0x7c, 0x82, 0x88, 0x88, 0x87, 0x87, 0x88, 0x8b, + 0x8b, 0x86, 0x81, 0x7e, 0x7f, 0x83, 0x87, 0x88, 0x84, 0x7c, 0x79, + 0x79, 0x7a, 0x7b, 0x79, 0x76, 0x74, 0x72, 0x71, 0x70, 0x70, 0x6e, + 0x6d, 0x6e, 0x6f, 0x6e, 0x6b, 0x67, 0x66, 0x6a, 0x6e, 0x6f, 0x6d, + 0x69, 0x63, 0x5f, 0x64, 0x66, 0x7a, 0xa9, 0xbe, 0xb6, 0x9e, 0x78, + 0x64, 0x71, 0x88, 0x9a, 0x9f, 0x8e, 0x84, 0x89, 0x8c, 0x8f, 0x8c, + 0x82, 0x80, 0x82, 0x83, 0x82, 0x81, 0x7a, 0x7c, 0x85, 0x89, 0x8d, + 0x8a, 0x7e, 0x78, 0x76, 0x76, 0x79, 0x7a, 0x7d, 0x7f, 0x7f, 0x7f, + 0x81, 0x86, 0x87, 0x85, 0x82, 0x7f, 0x7e, 0x82, 0x88, 0x87, 0x85, + 0x86, 0x88, 0x86, 0x83, 0x7f, 0x7d, 0x81, 0x80, 0x7d, 0x7c, 0x7b, + 0x7b, 0x7b, 0x7a, 0x78, 0x75, 0x73, 0x71, 0x71, 0x75, 0x78, 0x77, + 0x75, 0x72, 0x71, 0x72, 0x72, 0x70, 0x6d, 0x6b, 0x6b, 0x6c, 0x6f, + 0x70, 0x6f, 0x6d, 0x69, 0x69, 0x68, 0x6b, 0x6a, 0x76, 0xa7, 0xbc, + 0xad, 0x93, 0x77, 0x70, 0x7e, 0x8c, 0x91, 0x91, 0x8a, 0x89, 0x90, + 0x90, 0x88, 0x83, 0x81, 0x85, 0x8c, 0x89, 0x7f, 0x78, 0x79, 0x82, + 0x8a, 0x88, 0x84, 0x83, 0x82, 0x81, 0x7d, 0x76, 0x70, 0x70, 0x76, + 0x7d, 0x84, 0x86, 0x88, 0x88, 0x85, 0x7e, 0x78, 0x79, 0x80, 0x87, + 0x88, 0x86, 0x84, 0x86, 0x87, 0x87, 0x85, 0x83, 0x80, 0x80, 0x83, + 0x80, 0x7d, 0x7d, 0x7e, 0x7c, 0x78, 0x76, 0x78, 0x79, 0x78, 0x76, + 0x75, 0x74, 0x74, 0x75, 0x74, 0x72, 0x74, 0x74, 0x71, 0x71, 0x72, + 0x72, 0x72, 0x72, 0x6e, 0x70, 0x73, 0x72, 0x70, 0x6e, 0x6e, 0x73, + 0x72, 0x6d, 0x6e, 0x81, 0xaa, 0xb5, 0x9e, 0x8b, 0x86, 0x8b, 0x90, + 0x85, 0x7c, 0x87, 0x92, 0x98, 0x94, 0x86, 0x82, 0x8a, 0x8a, 0x83, + 0x7e, 0x7b, 0x7f, 0x84, 0x84, 0x81, 0x81, 0x84, 0x86, 0x81, 0x7b, + 0x7e, 0x80, 0x7e, 0x7a, 0x77, 0x78, 0x7a, 0x7e, 0x81, 0x83, 0x86, + 0x87, 0x86, 0x82, 0x85, 0x88, 0x88, 0x88, 0x86, 0x83, 0x83, 0x82, + 0x82, 0x84, 0x81, 0x80, 0x81, 0x7b, 0x78, 0x78, 0x77, 0x78, 0x79, + 0x77, 0x76, 0x77, 0x73, 0x72, 0x72, 0x71, 0x75, 0x77, 0x73, 0x72, + 0x73, 0x74, 0x73, 0x71, 0x73, 0x73, 0x71, 0x74, 0x77, 0x75, 0x75, + 0x75, 0x74, 0x75, 0x76, 0x74, 0x75, 0x77, 0x77, 0x77, 0x77, 0x7b, + 0x8f, 0xa1, 0x9f, 0x98, 0x97, 0x96, 0x93, 0x8b, 0x84, 0x88, 0x91, + 0x92, 0x8c, 0x8a, 0x8a, 0x8d, 0x8b, 0x84, 0x82, 0x84, 0x82, 0x7d, + 0x7d, 0x7f, 0x82, 0x85, 0x81, 0x7f, 0x80, 0x81, 0x80, 0x7e, 0x7b, + 0x7b, 0x7a, 0x74, 0x74, 0x7a, 0x80, 0x81, 0x81, 0x87, 0x89, 0x8a, + 0x87, 0x86, 0x86, 0x85, 0x82, 0x7e, 0x80, 0x81, 0x7f, 0x82, 0x84, + 0x81, 0x7d, 0x7b, 0x79, 0x79, 0x7a, 0x79, 0x78, 0x78, 0x79, 0x79, + 0x77, 0x75, 0x75, 0x75, 0x74, 0x72, 0x72, 0x75, 0x74, 0x70, 0x70, + 0x74, 0x75, 0x73, 0x72, 0x73, 0x74, 0x74, 0x75, 0x73, 0x73, 0x74, + 0x74, 0x73, 0x74, 0x75, 0x76, 0x74, 0x6f, 0x74, 0x75, 0x7d, 0x8b, + 0x84, 0x82, 0x8c, 0x94, 0x96, 0x8d, 0x91, 0x9a, 0x98, 0x90, 0x8d, + 0x90, 0x91, 0x8e, 0x89, 0x8b, 0x8e, 0x89, 0x86, 0x88, 0x88, 0x85, + 0x81, 0x81, 0x84, 0x83, 0x7f, 0x7d, 0x81, 0x84, 0x7f, 0x7c, 0x80, + 0x81, 0x7c, 0x79, 0x7b, 0x7a, 0x78, 0x7a, 0x7c, 0x7c, 0x7d, 0x81, + 0x85, 0x83, 0x84, 0x87, 0x85, 0x83, 0x84, 0x86, 0x87, 0x84, 0x84, + 0x89, 0x85, 0x7f, 0x81, 0x81, 0x7f, 0x7c, 0x7b, 0x7e, 0x7f, 0x79, + 0x78, 0x7c, 0x7b, 0x77, 0x76, 0x78, 0x76, 0x72, 0x73, 0x73, 0x71, + 0x71, 0x72, 0x72, 0x71, 0x74, 0x72, 0x6f, 0x73, 0x75, 0x72, 0x74, + 0x76, 0x74, 0x73, 0x73, 0x73, 0x72, 0x74, 0x76, 0x74, 0x73, 0x71, + 0x70, 0x70, 0x6f, 0x72, 0x82, 0x84, 0x7b, 0x80, 0x85, 0x80, 0x8e, + 0x99, 0x8e, 0x96, 0xa5, 0x9d, 0x96, 0x96, 0x96, 0x96, 0x94, 0x90, + 0x91, 0x91, 0x8a, 0x86, 0x89, 0x88, 0x81, 0x7e, 0x80, 0x82, 0x82, + 0x7f, 0x82, 0x87, 0x84, 0x7e, 0x7f, 0x7f, 0x7c, 0x7a, 0x78, 0x79, + 0x7a, 0x78, 0x77, 0x7a, 0x7c, 0x7b, 0x7d, 0x82, 0x85, 0x84, 0x86, + 0x89, 0x8a, 0x88, 0x87, 0x87, 0x86, 0x84, 0x81, 0x80, 0x80, 0x7f, + 0x7e, 0x7e, 0x7d, 0x7b, 0x79, 0x78, 0x77, 0x76, 0x75, 0x74, 0x75, + 0x73, 0x72, 0x73, 0x73, 0x71, 0x70, 0x72, 0x73, 0x73, 0x73, 0x73, + 0x75, 0x74, 0x74, 0x76, 0x74, 0x74, 0x74, 0x75, 0x76, 0x76, 0x78, + 0x78, 0x77, 0x79, 0x79, 0x78, 0x78, 0x79, 0x78, 0x78, 0x77, 0x77, + 0x75, 0x7a, 0x81, 0x7f, 0x7d, 0x81, 0x84, 0x80, 0x7e, 0x7d, 0x83, + 0x8b, 0x89, 0x8a, 0x91, 0x95, 0x94, 0x97, 0x99, 0x9b, 0x9e, 0x9e, + 0x9c, 0x9b, 0x9b, 0x98, 0x94, 0x92, 0x8f, 0x8b, 0x88, 0x84, 0x81, + 0x80, 0x7f, 0x7e, 0x7c, 0x7c, 0x7c, 0x7c, 0x7a, 0x78, 0x79, 0x7a, + 0x79, 0x78, 0x79, 0x7b, 0x7c, 0x7b, 0x7c, 0x7d, 0x7e, 0x80, 0x82, + 0x83, 0x84, 0x85, 0x86, 0x86, 0x86, 0x86, 0x84, 0x84, 0x83, 0x80, + 0x7f, 0x7e, 0x7d, 0x7b, 0x7a, 0x79, 0x78, 0x77, 0x76, 0x75, 0x75, + 0x74, 0x73, 0x73, 0x73, 0x72, 0x72, 0x72, 0x72, 0x72, 0x73, 0x72, + 0x71, 0x73, 0x74, 0x72, 0x72, 0x73, 0x75, 0x76, 0x76, 0x77, 0x79, + 0x7a, 0x7a, 0x7a, 0x7d, 0x7c, 0x7b, 0x7d, 0x7e, 0x7d, 0x7d, 0x7d, + 0x7c, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7e, 0x7e, 0x7d, 0x7b, 0x7a, + 0x79, 0x79, 0x7f, 0x82, 0x80, 0x84, 0x8d, 0x8e, 0x8d, 0x92, 0x96, + 0x99, 0x9c, 0x9e, 0x9c, 0x9c, 0x9f, 0x9e, 0x9b, 0x98, 0x95, 0x95, + 0x91, 0x8c, 0x89, 0x8a, 0x89, 0x84, 0x81, 0x81, 0x7f, 0x7d, 0x7c, + 0x7a, 0x7a, 0x7a, 0x78, 0x77, 0x78, 0x77, 0x77, 0x79, 0x79, 0x79, + 0x7b, 0x7d, 0x7d, 0x7e, 0x80, 0x7f, 0x7f, 0x80, 0x81, 0x80, 0x7f, + 0x80, 0x81, 0x80, 0x7f, 0x7f, 0x7f, 0x7e, 0x7d, 0x7c, 0x7c, 0x7b, + 0x7a, 0x7a, 0x79, 0x78, 0x77, 0x76, 0x75, 0x74, 0x74, 0x73, 0x73, + 0x72, 0x71, 0x72, 0x72, 0x70, 0x71, 0x72, 0x73, 0x72, 0x73, 0x74, + 0x74, 0x75, 0x75, 0x76, 0x77, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7f, + 0x80, 0x7f, 0x81, 0x82, 0x82, 0x81, 0x82, 0x81, 0x80, 0x81, 0x81, + 0x81, 0x82, 0x81, 0x80, 0x80, 0x7f, 0x7d, 0x7e, 0x80, 0x81, 0x82, + 0x84, 0x86, 0x89, 0x8b, 0x8b, 0x8d, 0x90, 0x91, 0x93, 0x93, 0x93, + 0x94, 0x94, 0x92, 0x90, 0x8f, 0x8e, 0x8d, 0x8c, 0x8a, 0x89, 0x89, + 0x88, 0x86, 0x85, 0x85, 0x84, 0x83, 0x82, 0x81, 0x81, 0x80, 0x7f, + 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7d, 0x7e, + 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, + 0x7e, 0x7e, 0x7e, 0x7e, 0x7d, 0x7d, 0x7d, 0x7d, 0x7c, 0x7b, 0x7b, + 0x7a, 0x7a, 0x79, 0x78, 0x77, 0x77, 0x75, 0x75, 0x74, 0x73, 0x73, + 0x73, 0x73, 0x73, 0x73, 0x73, 0x74, 0x75, 0x75, 0x76, 0x77, 0x78, + 0x79, 0x7a, 0x7a, 0x7b, 0x7d, 0x7e, 0x7e, 0x7e, 0x7f, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x81, 0x81, 0x82, 0x83, 0x85, + 0x86, 0x87, 0x87, 0x89, 0x8a, 0x8b, 0x8b, 0x8d, 0x8d, 0x8d, 0x8e, + 0x8d, 0x8d, 0x8c, 0x8c, 0x8b, 0x8a, 0x89, 0x88, 0x87, 0x86, 0x85, + 0x85, 0x83, 0x82, 0x81, 0x80, 0x80, 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, + 0x7e, 0x7d, 0x7d, 0x7d, 0x7d, 0x7e, 0x7e, 0x7d, 0x7d, 0x7e, 0x7d, + 0x7d, 0x7d, 0x7c, 0x7c, 0x7c, 0x7c, 0x7b, 0x7b, 0x7b, 0x7a, 0x7a, + 0x79, 0x78, 0x78, 0x78, 0x77, 0x77, 0x76, 0x76, 0x76, 0x76, 0x76, + 0x76, 0x77, 0x77, 0x78, 0x78, 0x79, 0x7a, 0x7b, 0x7b, 0x7c, 0x7d, + 0x7d, 0x7d, 0x7e, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, + 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, + 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, + 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, + 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, + }, + }, + "ru": [][]byte{ + { // 0 + 0x7f, 0x7f, 0x7e, 0x7f, 0x7f, 0x7e, 0x7f, 0x7e, 0x7f, 0x7f, 0x7e, + 0x7f, 0x7e, 0x7f, 0x7d, 0x7e, 0x7d, 0x7e, 0x7e, 0x7e, 0x7d, 0x7e, + 0x7e, 0x7d, 0x7f, 0x7e, 0x7f, 0x7e, 0x80, 0x80, 0x80, 0x81, 0x80, + 0x82, 0x81, 0x82, 0x82, 0x83, 0x82, 0x83, 0x83, 0x82, 0x83, 0x81, + 0x82, 0x81, 0x80, 0x80, 0x7f, 0x7f, 0x7e, 0x7e, 0x7d, 0x7e, 0x7c, + 0x7d, 0x7d, 0x7e, 0x7d, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7e, 0x7f, 0x7e, 0x7e, 0x7d, + 0x7c, 0x7b, 0x7b, 0x7a, 0x7a, 0x79, 0x7b, 0x7b, 0x7d, 0x7e, 0x7f, + 0x81, 0x82, 0x84, 0x85, 0x85, 0x87, 0x87, 0x86, 0x87, 0x86, 0x84, + 0x84, 0x83, 0x81, 0x81, 0x7f, 0x7f, 0x7e, 0x7e, 0x7d, 0x7d, 0x7c, + 0x7d, 0x7d, 0x7c, 0x7d, 0x7d, 0x7e, 0x7d, 0x7f, 0x7e, 0x7f, 0x7f, + 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x7f, + 0x7e, 0x7f, 0x7d, 0x7d, 0x7b, 0x7b, 0x7a, 0x78, 0x79, 0x79, 0x79, + 0x7a, 0x7b, 0x7d, 0x7f, 0x81, 0x84, 0x85, 0x86, 0x87, 0x87, 0x89, + 0x89, 0x88, 0x88, 0x85, 0x85, 0x83, 0x82, 0x81, 0x80, 0x7f, 0x7e, + 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7c, 0x7d, 0x7d, 0x7e, 0x7d, + 0x7f, 0x7e, 0x7f, 0x7e, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x80, + 0x7f, 0x80, 0x7e, 0x7f, 0x7e, 0x7f, 0x7e, 0x7e, 0x7c, 0x7c, 0x7b, + 0x7a, 0x79, 0x78, 0x79, 0x79, 0x79, 0x7b, 0x7b, 0x7e, 0x7f, 0x83, + 0x84, 0x86, 0x86, 0x88, 0x88, 0x89, 0x89, 0x88, 0x87, 0x86, 0x84, + 0x82, 0x82, 0x80, 0x7f, 0x7d, 0x7d, 0x7d, 0x7c, 0x7c, 0x7d, 0x7c, + 0x7d, 0x7d, 0x7d, 0x7e, 0x7e, 0x7e, 0x7f, 0x7e, 0x7f, 0x7f, 0x80, + 0x81, 0x80, 0x81, 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x7e, 0x7f, 0x7e, + 0x7e, 0x7e, 0x7e, 0x7d, 0x7b, 0x7a, 0x78, 0x79, 0x77, 0x78, 0x78, + 0x7a, 0x79, 0x7c, 0x7d, 0x81, 0x82, 0x8a, 0x8a, 0x8c, 0x8c, 0x8e, + 0x8d, 0x8b, 0x8a, 0x86, 0x85, 0x81, 0x81, 0x7f, 0x7d, 0x7b, 0x79, + 0x79, 0x78, 0x7a, 0x79, 0x7b, 0x7a, 0x7c, 0x7c, 0x7e, 0x7e, 0x7f, + 0x80, 0x7f, 0x81, 0x81, 0x82, 0x82, 0x82, 0x81, 0x81, 0x80, 0x80, + 0x7f, 0x7f, 0x7e, 0x7e, 0x7c, 0x7d, 0x7c, 0x7d, 0x7c, 0x7d, 0x7a, + 0x78, 0x76, 0x77, 0x76, 0x74, 0x76, 0x77, 0x77, 0x78, 0x7d, 0x81, + 0x84, 0x87, 0x89, 0x8b, 0x8a, 0x8d, 0x8f, 0x8f, 0x8d, 0x8b, 0x88, + 0x86, 0x82, 0x81, 0x80, 0x7d, 0x7b, 0x79, 0x7a, 0x78, 0x78, 0x7a, + 0x79, 0x7a, 0x79, 0x7c, 0x7c, 0x7d, 0x7f, 0x7f, 0x80, 0x80, 0x82, + 0x81, 0x83, 0x83, 0x82, 0x82, 0x80, 0x81, 0x80, 0x7f, 0x7f, 0x7d, + 0x7d, 0x7c, 0x7d, 0x7d, 0x7c, 0x7d, 0x7b, 0x78, 0x75, 0x77, 0x75, + 0x74, 0x74, 0x77, 0x77, 0x76, 0x7a, 0x7e, 0x82, 0x84, 0x89, 0x8a, + 0x8b, 0x8c, 0x8f, 0x8f, 0x8f, 0x8d, 0x8a, 0x88, 0x84, 0x83, 0x80, + 0x7f, 0x7c, 0x79, 0x79, 0x77, 0x78, 0x79, 0x79, 0x79, 0x78, 0x7a, + 0x7b, 0x7d, 0x7d, 0x80, 0x81, 0x80, 0x82, 0x82, 0x83, 0x84, 0x84, + 0x83, 0x83, 0x82, 0x82, 0x81, 0x80, 0x7f, 0x7e, 0x7d, 0x7c, 0x7c, + 0x7d, 0x7c, 0x7c, 0x7a, 0x76, 0x75, 0x76, 0x75, 0x72, 0x75, 0x76, + 0x76, 0x76, 0x7c, 0x80, 0x83, 0x85, 0x8a, 0x8a, 0x8c, 0x8e, 0x90, + 0x90, 0x8e, 0x8d, 0x89, 0x87, 0x83, 0x82, 0x80, 0x7e, 0x7b, 0x7a, + 0x78, 0x78, 0x78, 0x78, 0x7a, 0x78, 0x7a, 0x7a, 0x7b, 0x7d, 0x7e, + 0x81, 0x80, 0x81, 0x81, 0x83, 0x83, 0x85, 0x84, 0x84, 0x82, 0x82, + 0x82, 0x80, 0x80, 0x7f, 0x7f, 0x7d, 0x7c, 0x7d, 0x7c, 0x7d, 0x7a, + 0x76, 0x73, 0x75, 0x74, 0x71, 0x74, 0x76, 0x74, 0x75, 0x7a, 0x7f, + 0x81, 0x86, 0x89, 0x8b, 0x8c, 0x8e, 0x91, 0x90, 0x90, 0x8e, 0x8c, + 0x89, 0x84, 0x84, 0x81, 0x7f, 0x7d, 0x7a, 0x79, 0x76, 0x77, 0x78, + 0x79, 0x78, 0x79, 0x7a, 0x7a, 0x7c, 0x7d, 0x80, 0x80, 0x80, 0x82, + 0x82, 0x84, 0x84, 0x85, 0x83, 0x83, 0x82, 0x83, 0x82, 0x80, 0x80, + 0x7e, 0x7d, 0x7d, 0x7c, 0x7c, 0x7a, 0x76, 0x72, 0x74, 0x72, 0x6f, + 0x72, 0x74, 0x73, 0x72, 0x79, 0x7e, 0x80, 0x85, 0x89, 0x8c, 0x8b, + 0x8e, 0x92, 0x91, 0x92, 0x91, 0x8e, 0x8a, 0x87, 0x84, 0x84, 0x81, + 0x7c, 0x7c, 0x79, 0x75, 0x76, 0x78, 0x77, 0x77, 0x77, 0x79, 0x78, + 0x7a, 0x7c, 0x7f, 0x7e, 0x80, 0x81, 0x83, 0x83, 0x86, 0x85, 0x86, + 0x84, 0x85, 0x83, 0x83, 0x81, 0x82, 0x81, 0x7e, 0x7e, 0x7c, 0x7b, + 0x76, 0x73, 0x74, 0x72, 0x6d, 0x6e, 0x72, 0x70, 0x70, 0x74, 0x7b, + 0x7e, 0x83, 0x89, 0x8b, 0x8c, 0x8e, 0x93, 0x92, 0x93, 0x93, 0x92, + 0x8d, 0x89, 0x86, 0x85, 0x80, 0x7e, 0x7d, 0x79, 0x76, 0x75, 0x76, + 0x77, 0x74, 0x77, 0x78, 0x76, 0x78, 0x7a, 0x7e, 0x7e, 0x7f, 0x83, + 0x82, 0x83, 0x84, 0x87, 0x86, 0x86, 0x85, 0x85, 0x83, 0x83, 0x82, + 0x82, 0x7f, 0x7e, 0x7b, 0x75, 0x72, 0x72, 0x70, 0x6a, 0x6d, 0x6e, + 0x6c, 0x6d, 0x74, 0x78, 0x7c, 0x82, 0x87, 0x8b, 0x8b, 0x91, 0x94, + 0x94, 0x94, 0x95, 0x92, 0x8f, 0x8a, 0x89, 0x86, 0x83, 0x7f, 0x7d, + 0x7a, 0x75, 0x74, 0x75, 0x75, 0x73, 0x76, 0x77, 0x74, 0x76, 0x79, + 0x7d, 0x7d, 0x81, 0x83, 0x83, 0x85, 0x87, 0x88, 0x88, 0x87, 0x88, + 0x86, 0x86, 0x85, 0x82, 0x7f, 0x7a, 0x75, 0x6d, 0x6c, 0x6e, 0x6d, + 0x6c, 0x6e, 0x70, 0x69, 0x69, 0x71, 0x7a, 0x80, 0x8c, 0x92, 0x8e, + 0x8e, 0x92, 0x99, 0x9a, 0x9c, 0x9a, 0x90, 0x85, 0x7e, 0x7e, 0x7c, + 0x7a, 0x78, 0x71, 0x6a, 0x6a, 0x72, 0x79, 0x7d, 0x7f, 0x7e, 0x7d, + 0x80, 0x88, 0x8e, 0x8c, 0x8b, 0x88, 0x85, 0x84, 0x88, 0x86, 0x80, + 0x7c, 0x7b, 0x7d, 0x7e, 0x80, 0x7d, 0x7a, 0x75, 0x5c, 0x42, 0x4b, + 0x5b, 0x66, 0x78, 0x81, 0x85, 0x84, 0x92, 0xac, 0xb0, 0xa5, 0x9f, + 0x8b, 0x77, 0x78, 0x7e, 0x7e, 0x75, 0x71, 0x78, 0x79, 0x7f, 0x8f, + 0x8e, 0x86, 0x81, 0x80, 0x7e, 0x7b, 0x7f, 0x7d, 0x78, 0x79, 0x81, + 0x86, 0x88, 0x88, 0x86, 0x7f, 0x7f, 0x80, 0x81, 0x7e, 0x7e, 0x7d, + 0x7f, 0x81, 0x83, 0x86, 0x84, 0x85, 0x88, 0x86, 0x84, 0x7e, 0x76, + 0x57, 0x34, 0x3c, 0x4f, 0x5c, 0x78, 0x88, 0x88, 0x8a, 0x96, 0xaf, + 0xb4, 0xac, 0xa1, 0x86, 0x6e, 0x6e, 0x78, 0x7a, 0x7c, 0x7a, 0x7b, + 0x7d, 0x82, 0x91, 0x8f, 0x86, 0x7e, 0x74, 0x6f, 0x6f, 0x79, 0x7e, + 0x7d, 0x83, 0x88, 0x8a, 0x8e, 0x8d, 0x89, 0x7f, 0x7b, 0x7c, 0x7e, + 0x7f, 0x82, 0x81, 0x81, 0x81, 0x85, 0x89, 0x8a, 0x8b, 0x85, 0x7e, + 0x77, 0x70, 0x3b, 0x50, 0x66, 0x8f, 0x97, 0x97, 0x8f, 0x8b, 0xad, + 0xa9, 0x9d, 0x96, 0x71, 0x5c, 0x5c, 0x6b, 0x88, 0x89, 0x8b, 0x93, + 0x85, 0x87, 0x92, 0x91, 0x89, 0x75, 0x68, 0x63, 0x62, 0x6e, 0x86, + 0x88, 0x84, 0x86, 0x86, 0x8c, 0x8b, 0x8d, 0x87, 0x79, 0x77, 0x7d, + 0x81, 0x85, 0x85, 0x89, 0x87, 0x88, 0x8c, 0x8e, 0x89, 0x84, 0x7f, + 0x7c, 0x77, 0x58, 0x2b, 0x3a, 0x57, 0x6a, 0x8f, 0x95, 0x98, 0x92, + 0x8a, 0xab, 0xaf, 0x95, 0x89, 0x69, 0x5d, 0x61, 0x71, 0x8e, 0x8a, + 0x82, 0x8d, 0x8d, 0x92, 0x97, 0x91, 0x80, 0x6a, 0x5f, 0x6b, 0x71, + 0x73, 0x82, 0x84, 0x87, 0x87, 0x8b, 0x92, 0x84, 0x78, 0x79, 0x76, + 0x7e, 0x7f, 0x81, 0x80, 0x7b, 0x87, 0x90, 0x8f, 0x91, 0x8c, 0x85, + 0x82, 0x82, 0x85, 0x82, 0x7b, 0x79, 0x6a, 0x38, 0x34, 0x64, 0x74, + 0x82, 0x8a, 0x83, 0x92, 0x89, 0xa0, 0xbb, 0x92, 0x7a, 0x6d, 0x69, + 0x7a, 0x77, 0x80, 0x84, 0x70, 0x81, 0x9c, 0xa2, 0x9a, 0x83, 0x77, + 0x78, 0x6e, 0x76, 0x7e, 0x6b, 0x69, 0x76, 0x8c, 0x99, 0x8f, 0x8a, + 0x7f, 0x6f, 0x7d, 0x7e, 0x76, 0x71, 0x71, 0x84, 0x88, 0x8a, 0x8c, + 0x81, 0x7c, 0x86, 0x8d, 0x92, 0x88, 0x81, 0x7f, 0x80, 0x89, 0x8c, + 0x85, 0x7f, 0x76, 0x5d, 0x30, 0x47, 0x71, 0x6d, 0x75, 0x72, 0x82, + 0x9d, 0x98, 0xb3, 0xab, 0x7d, 0x7b, 0x7c, 0x84, 0x7f, 0x62, 0x6d, + 0x77, 0x7a, 0x9b, 0x9e, 0x92, 0x85, 0x80, 0x94, 0x90, 0x77, 0x6d, + 0x65, 0x65, 0x77, 0x82, 0x83, 0x7c, 0x79, 0x8d, 0x98, 0x8a, 0x7b, + 0x70, 0x71, 0x78, 0x79, 0x79, 0x71, 0x76, 0x8a, 0x8f, 0x8d, 0x8a, + 0x8a, 0x8f, 0x8f, 0x8d, 0x8d, 0x82, 0x81, 0x7f, 0x7e, 0x7d, 0x7c, + 0x7d, 0x7f, 0x78, 0x76, 0x56, 0x2d, 0x63, 0x7d, 0x66, 0x6e, 0x69, + 0x88, 0xa5, 0x99, 0xb5, 0x9c, 0x7e, 0x9f, 0x98, 0x8a, 0x72, 0x59, + 0x74, 0x74, 0x72, 0x83, 0x76, 0x79, 0x93, 0x9e, 0x9e, 0x85, 0x7d, + 0x88, 0x83, 0x74, 0x73, 0x69, 0x61, 0x72, 0x7c, 0x7f, 0x7d, 0x7d, + 0x91, 0x94, 0x8a, 0x88, 0x81, 0x7e, 0x81, 0x78, 0x72, 0x70, 0x75, + 0x7e, 0x79, 0x7b, 0x85, 0x8b, 0x8c, 0x8d, 0x89, 0x89, 0x8a, 0x8b, + 0x85, 0x83, 0x81, 0x80, 0x7d, 0x7d, 0x7f, 0x7a, 0x7a, 0x62, 0x41, + 0x6d, 0x80, 0x4d, 0x63, 0x79, 0x70, 0x8a, 0x9e, 0x8f, 0x8a, 0x9b, + 0xa9, 0xa2, 0x8c, 0x86, 0x88, 0x81, 0x7a, 0x7e, 0x6c, 0x62, 0x78, + 0x80, 0x71, 0x7a, 0x86, 0x86, 0x88, 0x8e, 0x89, 0x88, 0x8e, 0x8d, + 0x81, 0x79, 0x79, 0x81, 0x7a, 0x74, 0x74, 0x71, 0x73, 0x7a, 0x76, + 0x70, 0x77, 0x81, 0x81, 0x84, 0x83, 0x85, 0x8d, 0x8d, 0x89, 0x89, + 0x87, 0x87, 0x83, 0x7c, 0x7c, 0x82, 0x83, 0x82, 0x82, 0x82, 0x86, + 0x89, 0x84, 0x86, 0x85, 0x84, 0x7d, 0x7b, 0x76, 0x50, 0x5f, 0x7d, + 0x56, 0x55, 0x6f, 0x66, 0x6e, 0x89, 0x88, 0x76, 0x9e, 0xb0, 0x8f, + 0x9d, 0xa5, 0x94, 0x99, 0x97, 0x86, 0x76, 0x82, 0x83, 0x69, 0x6b, + 0x72, 0x6e, 0x73, 0x77, 0x70, 0x6f, 0x81, 0x8f, 0x7f, 0x85, 0x91, + 0x8c, 0x91, 0x8f, 0x81, 0x7f, 0x86, 0x7f, 0x71, 0x75, 0x77, 0x70, + 0x74, 0x72, 0x6a, 0x73, 0x7f, 0x7b, 0x7a, 0x87, 0x8a, 0x85, 0x8d, + 0x8e, 0x8d, 0x95, 0x8e, 0x83, 0x86, 0x86, 0x7f, 0x7d, 0x7c, 0x76, + 0x7b, 0x7c, 0x78, 0x7f, 0x84, 0x81, 0x83, 0x83, 0x82, 0x81, 0x7e, + 0x62, 0x6b, 0x7e, 0x61, 0x5e, 0x69, 0x63, 0x70, 0x7d, 0x79, 0x75, + 0x91, 0x9d, 0x89, 0x9b, 0xa1, 0x98, 0xa2, 0x98, 0x8a, 0x8b, 0x91, + 0x88, 0x74, 0x75, 0x75, 0x6b, 0x73, 0x6b, 0x67, 0x75, 0x78, 0x76, + 0x77, 0x81, 0x87, 0x87, 0x8e, 0x86, 0x87, 0x91, 0x8a, 0x80, 0x83, + 0x83, 0x82, 0x7b, 0x7a, 0x76, 0x77, 0x75, 0x72, 0x71, 0x74, 0x76, + 0x77, 0x78, 0x80, 0x83, 0x87, 0x89, 0x8b, 0x8d, 0x8f, 0x8b, 0x8a, + 0x89, 0x85, 0x7e, 0x7e, 0x7d, 0x7d, 0x7b, 0x7a, 0x7f, 0x7f, 0x7d, + 0x80, 0x82, 0x81, 0x82, 0x7d, 0x7d, 0x7c, 0x69, 0x71, 0x7b, 0x63, + 0x69, 0x6b, 0x68, 0x73, 0x75, 0x79, 0x75, 0x8d, 0x93, 0x84, 0x98, + 0x9b, 0x94, 0xa1, 0x94, 0x91, 0x97, 0x8f, 0x88, 0x7f, 0x85, 0x7b, + 0x73, 0x76, 0x6a, 0x6d, 0x74, 0x69, 0x6d, 0x74, 0x7b, 0x7c, 0x7e, + 0x84, 0x84, 0x89, 0x8a, 0x80, 0x88, 0x86, 0x84, 0x82, 0x82, 0x83, + 0x82, 0x7e, 0x7c, 0x7b, 0x7a, 0x75, 0x73, 0x75, 0x76, 0x78, 0x76, + 0x79, 0x82, 0x83, 0x84, 0x89, 0x8d, 0x8e, 0x8c, 0x8b, 0x88, 0x87, + 0x85, 0x80, 0x80, 0x7f, 0x7c, 0x7a, 0x7a, 0x79, 0x7c, 0x7e, 0x7c, + 0x7e, 0x7f, 0x81, 0x7c, 0x82, 0x73, 0x6c, 0x80, 0x70, 0x6c, 0x71, + 0x6e, 0x77, 0x71, 0x78, 0x72, 0x7f, 0x89, 0x7b, 0x8b, 0x91, 0x90, + 0x96, 0x95, 0x94, 0x97, 0x94, 0x8e, 0x87, 0x89, 0x81, 0x7b, 0x79, + 0x72, 0x73, 0x72, 0x6d, 0x71, 0x75, 0x77, 0x75, 0x7b, 0x7d, 0x7f, + 0x82, 0x83, 0x82, 0x86, 0x84, 0x83, 0x82, 0x83, 0x83, 0x82, 0x81, + 0x7e, 0x7f, 0x7a, 0x75, 0x7a, 0x78, 0x77, 0x76, 0x79, 0x7c, 0x7e, + 0x7e, 0x84, 0x88, 0x88, 0x88, 0x89, 0x89, 0x87, 0x86, 0x82, 0x81, + 0x80, 0x7e, 0x7b, 0x7d, 0x7b, 0x7b, 0x7b, 0x7c, 0x7b, 0x7d, 0x7d, + 0x7d, 0x80, 0x7f, 0x81, 0x82, 0x88, 0x73, 0x79, 0x83, 0x6f, 0x73, + 0x6a, 0x70, 0x72, 0x6c, 0x74, 0x6d, 0x84, 0x7e, 0x7e, 0x8d, 0x8e, + 0x94, 0x90, 0x93, 0x91, 0x92, 0x8f, 0x87, 0x8a, 0x88, 0x85, 0x82, + 0x81, 0x80, 0x7c, 0x79, 0x75, 0x77, 0x76, 0x71, 0x72, 0x74, 0x77, + 0x79, 0x7b, 0x7e, 0x81, 0x83, 0x80, 0x84, 0x84, 0x82, 0x82, 0x80, + 0x81, 0x7d, 0x7f, 0x7c, 0x7b, 0x7c, 0x7c, 0x7b, 0x7c, 0x7c, 0x7b, + 0x7d, 0x7e, 0x80, 0x82, 0x82, 0x84, 0x85, 0x85, 0x86, 0x83, 0x84, + 0x82, 0x84, 0x80, 0x80, 0x7e, 0x7f, 0x7e, 0x7d, 0x7c, 0x7c, 0x7c, + 0x7d, 0x7b, 0x7d, 0x7d, 0x7e, 0x81, 0x7e, 0x7f, 0x7e, 0x7e, 0x7e, + 0x71, 0x7d, 0x78, 0x74, 0x76, 0x73, 0x7d, 0x74, 0x7b, 0x78, 0x7e, + 0x85, 0x7e, 0x84, 0x86, 0x8c, 0x88, 0x8c, 0x8f, 0x8e, 0x8f, 0x89, + 0x8a, 0x87, 0x85, 0x81, 0x7e, 0x7e, 0x7b, 0x78, 0x77, 0x78, 0x79, + 0x77, 0x78, 0x79, 0x7d, 0x7a, 0x7d, 0x7d, 0x7f, 0x7f, 0x7f, 0x81, + 0x83, 0x83, 0x84, 0x84, 0x84, 0x84, 0x81, 0x7d, 0x7d, 0x7c, 0x7d, + 0x79, 0x7a, 0x7a, 0x7a, 0x7a, 0x7b, 0x7e, 0x7d, 0x80, 0x80, 0x81, + 0x81, 0x84, 0x84, 0x82, 0x84, 0x81, 0x82, 0x83, 0x82, 0x83, 0x81, + 0x81, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x7b, 0x7e, 0x7d, 0x7e, 0x7d, + 0x7c, 0x7e, 0x7a, 0x7d, 0x7d, 0x7e, 0x7f, 0x7e, 0x80, 0x81, 0x82, + 0x83, 0x7f, 0x80, 0x80, 0x7d, 0x7e, 0x79, 0x7c, 0x79, 0x7a, 0x79, + 0x7c, 0x7e, 0x80, 0x82, 0x83, 0x84, 0x85, 0x85, 0x86, 0x85, 0x85, + 0x82, 0x83, 0x83, 0x82, 0x81, 0x80, 0x7f, 0x7f, 0x7e, 0x7e, 0x7f, + 0x80, 0x7d, 0x7e, 0x7d, 0x81, 0x80, 0x80, 0x80, 0x7e, 0x80, 0x7d, + 0x7e, 0x7d, 0x7d, 0x7d, 0x7b, 0x7b, 0x7d, 0x7e, 0x7e, 0x7f, 0x7e, + 0x7f, 0x7f, 0x81, 0x83, 0x81, 0x82, 0x81, 0x80, 0x7f, 0x7f, 0x7f, + 0x7d, 0x7e, 0x7e, 0x7e, 0x7f, 0x80, 0x7e, 0x80, 0x80, 0x81, 0x80, + 0x81, 0x82, 0x7e, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7e, 0x7f, + 0x7f, 0x7d, 0x7d, 0x7f, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, 0x80, + 0x7f, 0x80, 0x7f, 0x7e, 0x7d, 0x7d, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, + 0x7e, 0x80, 0x80, 0x82, 0x82, 0x82, 0x81, 0x81, 0x81, 0x80, 0x80, + 0x80, 0x7f, 0x7e, 0x7e, 0x7c, 0x7f, 0x7f, 0x81, 0x81, 0x80, 0x7f, + 0x82, 0x82, 0x80, 0x7d, 0x7e, 0x7f, 0x7e, 0x7e, 0x7f, 0x7e, 0x7f, + 0x7e, 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7e, + 0x7f, 0x7d, 0x80, 0x7d, 0x7f, 0x7e, 0x7f, 0x80, 0x7e, 0x80, 0x82, + 0x81, 0x80, 0x80, 0x7e, 0x80, 0x7f, 0x80, 0x81, 0x7f, 0x7e, 0x7f, + 0x7f, 0x81, 0x7f, 0x7f, 0x7c, 0x7e, 0x7d, 0x7b, 0x7e, 0x7c, 0x7e, + 0x7e, 0x7f, 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, 0x7d, 0x7e, 0x7d, + 0x7e, 0x7f, 0x7e, 0x80, 0x81, 0x81, 0x81, 0x83, 0x80, 0x81, 0x80, + 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x7e, 0x7e, 0x7f, 0x7e, + 0x7f, 0x7e, 0x7f, 0x7e, 0x7f, 0x7e, 0x80, 0x7f, 0x7f, 0x81, 0x7f, + 0x81, 0x80, 0x81, 0x80, 0x81, 0x80, 0x7f, 0x7f, 0x7f, 0x7e, 0x7f, + 0x7d, 0x7f, 0x80, 0x80, 0x7e, 0x80, 0x7f, 0x7f, 0x7f, 0x80, 0x80, + 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x80, 0x7f, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x7e, 0x7f, 0x7e, 0x7f, 0x7e, 0x80, 0x80, + 0x80, 0x7f, 0x7e, 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x7d, 0x7e, + 0x7e, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x81, 0x7f, 0x80, 0x80, 0x80, + 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, + 0x7f, 0x7f, 0x7e, 0x7f, 0x7e, 0x7f, 0x7e, 0x7f, 0x7f, 0x7f, 0x80, + 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, + 0x7e, 0x7e, 0x7f, 0x7e, 0x7f, 0x7f, + }, + { // 1 + 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, 0x7e, 0x7d, 0x7d, + 0x7d, 0x7d, 0x7f, 0x80, 0x80, 0x81, 0x81, 0x82, 0x82, 0x82, 0x80, + 0x80, 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, 0x81, 0x81, 0x80, 0x80, + 0x80, 0x81, 0x81, 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x80, 0x81, 0x81, 0x80, 0x7f, 0x7e, + 0x7f, 0x80, 0x81, 0x82, 0x82, 0x81, 0x80, 0x7f, 0x7e, 0x79, 0x50, + 0x36, 0x71, 0x90, 0x8d, 0xa6, 0x8b, 0x7b, 0x99, 0x8f, 0x7c, 0x6b, + 0x65, 0x78, 0x88, 0x9b, 0x97, 0x85, 0x8c, 0x8f, 0x86, 0x7f, 0x6f, + 0x66, 0x74, 0x84, 0x8a, 0x8b, 0x86, 0x83, 0x83, 0x81, 0x7e, 0x72, + 0x6f, 0x79, 0x7d, 0x84, 0x87, 0x7f, 0x80, 0x81, 0x7e, 0x7b, 0x77, + 0x7b, 0x81, 0x85, 0x85, 0x7e, 0x7c, 0x7d, 0x7f, 0x83, 0x84, 0x86, + 0x87, 0x85, 0x82, 0x7c, 0x7a, 0x7c, 0x7e, 0x83, 0x87, 0x88, 0x87, + 0x82, 0x7e, 0x7d, 0x7d, 0x7f, 0x80, 0x7f, 0x7f, 0x75, 0x4d, 0x41, + 0x7c, 0x8a, 0x85, 0xa3, 0x81, 0x7e, 0xa2, 0x89, 0x78, 0x6f, 0x6a, + 0x7a, 0x87, 0x95, 0x8b, 0x83, 0x94, 0x90, 0x86, 0x81, 0x6d, 0x69, + 0x7c, 0x81, 0x82, 0x88, 0x84, 0x88, 0x89, 0x84, 0x7e, 0x73, 0x74, + 0x78, 0x78, 0x81, 0x81, 0x81, 0x85, 0x80, 0x7e, 0x7d, 0x7c, 0x7d, + 0x80, 0x81, 0x80, 0x81, 0x80, 0x7e, 0x80, 0x82, 0x84, 0x87, 0x85, + 0x84, 0x81, 0x7e, 0x7c, 0x7d, 0x80, 0x84, 0x86, 0x85, 0x84, 0x83, + 0x81, 0x80, 0x81, 0x7f, 0x7c, 0x5e, 0x2b, 0x56, 0x93, 0x7b, 0x9f, + 0x9c, 0x6f, 0xa5, 0xa1, 0x78, 0x72, 0x61, 0x6e, 0x7f, 0x90, 0x90, + 0x7e, 0x94, 0x9e, 0x8d, 0x89, 0x76, 0x61, 0x74, 0x7f, 0x77, 0x82, + 0x83, 0x89, 0x93, 0x8a, 0x85, 0x76, 0x73, 0x77, 0x71, 0x79, 0x7d, + 0x7d, 0x87, 0x88, 0x82, 0x7f, 0x7f, 0x79, 0x78, 0x7e, 0x7f, 0x83, + 0x85, 0x80, 0x7f, 0x81, 0x82, 0x84, 0x87, 0x87, 0x86, 0x85, 0x7f, + 0x7b, 0x7c, 0x7d, 0x82, 0x85, 0x86, 0x88, 0x86, 0x84, 0x81, 0x7d, + 0x7b, 0x6c, 0x30, 0x3d, 0x8c, 0x78, 0x8d, 0xaa, 0x74, 0x9f, 0xb2, + 0x81, 0x73, 0x63, 0x6d, 0x76, 0x81, 0x8b, 0x7a, 0x92, 0xab, 0x95, + 0x8b, 0x82, 0x67, 0x72, 0x7b, 0x6a, 0x75, 0x7e, 0x8b, 0x96, 0x8d, + 0x8d, 0x80, 0x7f, 0x7e, 0x6a, 0x6c, 0x72, 0x77, 0x84, 0x84, 0x82, + 0x87, 0x88, 0x80, 0x7e, 0x7d, 0x7a, 0x7f, 0x7f, 0x7d, 0x80, 0x81, + 0x83, 0x86, 0x87, 0x85, 0x86, 0x87, 0x81, 0x80, 0x7d, 0x7b, 0x7f, + 0x81, 0x84, 0x88, 0x88, 0x86, 0x85, 0x7f, 0x79, 0x4c, 0x23, 0x6e, + 0x81, 0x67, 0x9d, 0x86, 0x8d, 0xc3, 0x9c, 0x7e, 0x6f, 0x75, 0x7a, + 0x69, 0x76, 0x70, 0x7d, 0xab, 0xa0, 0x8b, 0x97, 0x88, 0x82, 0x80, + 0x63, 0x62, 0x6d, 0x7d, 0x85, 0x7c, 0x8f, 0x96, 0x95, 0x93, 0x76, + 0x6f, 0x73, 0x71, 0x6f, 0x67, 0x71, 0x85, 0x8c, 0x8d, 0x8a, 0x8a, + 0x8a, 0x84, 0x78, 0x71, 0x78, 0x7e, 0x7e, 0x81, 0x87, 0x8b, 0x8e, + 0x89, 0x82, 0x83, 0x83, 0x7e, 0x7b, 0x7e, 0x80, 0x84, 0x87, 0x84, + 0x86, 0x87, 0x7b, 0x3a, 0x34, 0x88, 0x60, 0x61, 0x91, 0x6f, 0xaa, + 0xc0, 0x92, 0x8a, 0x88, 0x98, 0x75, 0x5f, 0x6c, 0x60, 0x82, 0x95, + 0x76, 0x90, 0xa9, 0x9b, 0x99, 0x81, 0x78, 0x7c, 0x72, 0x6d, 0x59, + 0x6e, 0x88, 0x85, 0x90, 0x89, 0x8d, 0x99, 0x89, 0x7a, 0x69, 0x69, + 0x70, 0x6b, 0x6e, 0x7b, 0x8d, 0x91, 0x8d, 0x8b, 0x89, 0x89, 0x7f, + 0x76, 0x79, 0x80, 0x82, 0x7f, 0x83, 0x87, 0x88, 0x85, 0x82, 0x84, + 0x87, 0x85, 0x80, 0x84, 0x83, 0x83, 0x80, 0x81, 0x56, 0x28, 0x7b, + 0x6d, 0x3e, 0x83, 0x6b, 0x8b, 0xbc, 0x94, 0x98, 0xa6, 0xb3, 0x8f, + 0x6d, 0x7e, 0x66, 0x6c, 0x74, 0x52, 0x79, 0x9b, 0x89, 0x93, 0x93, + 0x9d, 0xa4, 0x8d, 0x7d, 0x70, 0x7b, 0x73, 0x5e, 0x6b, 0x6d, 0x7d, + 0x84, 0x74, 0x7f, 0x92, 0x8e, 0x83, 0x83, 0x84, 0x88, 0x84, 0x77, + 0x7d, 0x84, 0x7c, 0x76, 0x7c, 0x82, 0x82, 0x81, 0x82, 0x8b, 0x90, + 0x88, 0x83, 0x87, 0x87, 0x80, 0x7c, 0x7c, 0x81, 0x7f, 0x7b, 0x7d, + 0x8a, 0x71, 0x3d, 0x76, 0x76, 0x44, 0x78, 0x58, 0x6a, 0xa4, 0x77, + 0x88, 0xa5, 0xb0, 0xa8, 0x96, 0x9f, 0x8c, 0x96, 0x82, 0x56, 0x7a, + 0x75, 0x63, 0x73, 0x67, 0x7e, 0x92, 0x85, 0x85, 0x94, 0x9d, 0x8c, + 0x8c, 0x85, 0x7c, 0x87, 0x73, 0x69, 0x75, 0x6e, 0x69, 0x71, 0x73, + 0x7d, 0x87, 0x82, 0x89, 0x96, 0x90, 0x8d, 0x8f, 0x8b, 0x8a, 0x83, + 0x79, 0x7c, 0x7e, 0x75, 0x72, 0x78, 0x7e, 0x81, 0x7f, 0x82, 0x8b, + 0x8c, 0x8a, 0x84, 0x89, 0x80, 0x5d, 0x74, 0x75, 0x56, 0x6d, 0x5f, + 0x5e, 0x7b, 0x6e, 0x6f, 0x83, 0x8f, 0x8e, 0x93, 0x9a, 0x95, 0xa6, + 0x9e, 0x8e, 0x9a, 0x90, 0x8a, 0x86, 0x7c, 0x7c, 0x7e, 0x79, 0x72, + 0x79, 0x79, 0x74, 0x79, 0x77, 0x78, 0x7c, 0x77, 0x78, 0x80, 0x7f, + 0x7f, 0x82, 0x83, 0x86, 0x88, 0x85, 0x87, 0x8a, 0x87, 0x82, 0x81, + 0x80, 0x80, 0x7f, 0x79, 0x7a, 0x7e, 0x7b, 0x7b, 0x7b, 0x7b, 0x7e, + 0x7f, 0x7e, 0x7d, 0x7f, 0x81, 0x80, 0x80, 0x7e, 0x7f, 0x82, 0x7e, + 0x7d, 0x7d, 0x7c, 0x7d, 0x7a, 0x7a, 0x7c, 0x7c, 0x7c, 0x7b, 0x7c, + 0x7f, 0x81, 0x80, 0x7e, 0x82, 0x85, 0x83, 0x86, 0x85, 0x85, 0x89, + 0x88, 0x86, 0x87, 0x88, 0x88, 0x87, 0x86, 0x85, 0x85, 0x84, 0x81, + 0x7f, 0x7d, 0x7c, 0x7b, 0x79, 0x79, 0x7b, 0x7c, 0x7d, 0x7b, 0x7c, + 0x7e, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, 0x7e, 0x7f, + 0x80, 0x81, 0x7f, 0x80, 0x82, 0x82, 0x81, 0x7e, 0x7d, 0x7d, 0x7a, + 0x77, 0x76, 0x78, 0x79, 0x78, 0x7b, 0x7e, 0x80, 0x83, 0x81, 0x82, + 0x84, 0x83, 0x83, 0x83, 0x84, 0x86, 0x87, 0x87, 0x89, 0x8a, 0x88, + 0x88, 0x88, 0x86, 0x86, 0x83, 0x80, 0x80, 0x7f, 0x7e, 0x7d, 0x7c, + 0x7c, 0x7c, 0x7c, 0x7a, 0x7b, 0x7b, 0x7a, 0x7b, 0x7b, 0x7c, 0x7d, + 0x7d, 0x7e, 0x7f, 0x80, 0x80, 0x81, 0x82, 0x83, 0x84, 0x84, 0x83, + 0x83, 0x80, 0x7e, 0x7d, 0x7a, 0x78, 0x77, 0x77, 0x79, 0x79, 0x7b, + 0x7d, 0x7f, 0x81, 0x80, 0x81, 0x82, 0x81, 0x81, 0x80, 0x81, 0x82, + 0x82, 0x84, 0x87, 0x88, 0x8a, 0x89, 0x87, 0x87, 0x86, 0x84, 0x83, + 0x81, 0x7f, 0x80, 0x7f, 0x7c, 0x7d, 0x7c, 0x7c, 0x7c, 0x7a, 0x7b, + 0x7c, 0x7b, 0x7c, 0x7c, 0x7e, 0x7f, 0x7f, 0x80, 0x80, 0x81, 0x80, + 0x7f, 0x7f, 0x7e, 0x7e, 0x7f, 0x7e, 0x80, 0x82, 0x81, 0x81, 0x7f, + 0x7d, 0x7e, 0x7b, 0x7a, 0x7b, 0x7b, 0x7b, 0x7b, 0x7c, 0x7d, 0x7e, + 0x7f, 0x7e, 0x7f, 0x81, 0x83, 0x85, 0x85, 0x86, 0x87, 0x89, 0x87, + 0x86, 0x85, 0x84, 0x83, 0x82, 0x80, 0x7f, 0x81, 0x81, 0x81, 0x80, + 0x7f, 0x80, 0x80, 0x7e, 0x7d, 0x7c, 0x7b, 0x7a, 0x79, 0x79, 0x79, + 0x7c, 0x7c, 0x7c, 0x7e, 0x7f, 0x81, 0x81, 0x80, 0x81, 0x83, 0x82, + 0x81, 0x81, 0x81, 0x81, 0x82, 0x7f, 0x7e, 0x7e, 0x7c, 0x79, 0x78, + 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7f, 0x81, 0x80, 0x80, 0x82, 0x83, + 0x83, 0x82, 0x81, 0x83, 0x85, 0x85, 0x85, 0x85, 0x84, 0x86, 0x85, + 0x83, 0x83, 0x83, 0x82, 0x81, 0x7f, 0x7f, 0x7e, 0x7c, 0x7d, 0x7c, + 0x7b, 0x7c, 0x7b, 0x7b, 0x7c, 0x7d, 0x7d, 0x7e, 0x7f, 0x80, 0x81, + 0x81, 0x80, 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x80, + 0x81, 0x82, 0x81, 0x80, 0x7f, 0x7e, 0x7c, 0x7c, 0x7a, 0x7a, 0x7b, + 0x7c, 0x7c, 0x7c, 0x7c, 0x7e, 0x7f, 0x80, 0x7f, 0x80, 0x82, 0x84, + 0x85, 0x85, 0x85, 0x86, 0x86, 0x85, 0x84, 0x82, 0x82, 0x82, 0x7f, + 0x80, 0x80, 0x80, 0x81, 0x80, 0x80, 0x80, 0x7f, 0x7e, 0x7d, 0x7d, + 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7e, 0x7e, 0x7e, 0x7f, 0x7e, 0x7f, + 0x7f, 0x7f, 0x80, 0x80, 0x81, 0x80, 0x80, 0x81, 0x81, 0x80, 0x7e, + 0x7e, 0x7e, 0x7d, 0x7d, 0x7d, 0x7e, 0x7f, 0x7f, 0x7f, 0x7e, 0x7e, + 0x7f, 0x7e, 0x7d, 0x7c, 0x7d, 0x7e, 0x7e, 0x7e, 0x7e, 0x80, 0x81, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x83, 0x83, 0x84, 0x85, 0x84, 0x83, + 0x83, 0x83, 0x82, 0x81, 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, + 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7d, 0x7c, 0x7d, 0x7c, 0x7c, 0x7e, + 0x7e, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x81, 0x81, + 0x81, 0x82, 0x82, 0x80, 0x7f, 0x7f, 0x7f, 0x7d, 0x7d, 0x7c, 0x7c, + 0x7c, 0x7a, 0x7b, 0x7c, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x82, 0x81, + 0x82, 0x83, 0x83, 0x83, 0x82, 0x82, 0x81, 0x81, 0x81, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x81, 0x82, 0x82, 0x7f, 0x80, 0x80, 0x7f, + 0x7f, 0x7c, 0x7c, 0x7d, 0x7e, 0x7d, 0x7e, 0x7f, 0x7f, 0x7f, 0x7e, + 0x80, 0x7d, 0x7e, 0x7f, 0x7d, 0x80, 0x80, 0x80, 0x81, 0x81, 0x80, + 0x80, 0x80, 0x7f, 0x7f, 0x7d, 0x7d, 0x7f, 0x7d, 0x7c, 0x7e, 0x7c, + 0x7e, 0x7d, 0x7b, 0x7e, 0x7e, 0x7d, 0x7e, 0x7e, 0x80, 0x81, 0x80, + 0x80, 0x82, 0x82, 0x82, 0x82, 0x82, 0x83, 0x83, 0x81, 0x81, 0x81, + 0x82, 0x82, 0x82, 0x82, 0x80, 0x81, 0x80, 0x80, 0x7f, 0x80, 0x80, + 0x7f, 0x80, 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x7d, 0x7d, 0x7e, 0x7d, + 0x80, 0x7e, 0x7e, 0x81, 0x7d, 0x7f, 0x80, 0x7d, 0x7f, 0x7f, 0x7d, + 0x80, 0x7f, 0x80, 0x82, 0x7e, 0x7f, 0x83, 0x7e, 0x7e, 0x80, 0x79, + 0x7e, 0x7b, 0x76, 0x7d, 0x79, 0x7b, 0x7f, 0x7c, 0x83, 0x82, 0x80, + 0x85, 0x83, 0x84, 0x83, 0x81, 0x83, 0x83, 0x82, 0x81, 0x83, 0x82, + 0x82, 0x83, 0x7f, 0x84, 0x81, 0x7f, 0x82, 0x7f, 0x81, 0x7e, 0x7e, + 0x7f, 0x80, 0x7c, 0x7f, 0x7e, 0x7d, 0x80, 0x7d, 0x81, 0x80, 0x7e, + 0x80, 0x81, 0x7c, 0x83, 0x7b, 0x7e, 0x80, 0x7c, 0x7f, 0x7d, 0x81, + 0x7e, 0x85, 0x80, 0x7b, 0x83, 0x80, 0x76, 0x7f, 0x78, 0x77, 0x80, + 0x70, 0x7d, 0x7f, 0x78, 0x84, 0x7d, 0x7f, 0x89, 0x7f, 0x81, 0x85, + 0x82, 0x85, 0x81, 0x82, 0x86, 0x86, 0x83, 0x82, 0x87, 0x83, 0x82, + 0x80, 0x7f, 0x82, 0x80, 0x7b, 0x7e, 0x81, 0x7d, 0x7c, 0x7c, 0x7f, + 0x7c, 0x7c, 0x7f, 0x7f, 0x81, 0x82, 0x7f, 0x83, 0x83, 0x7e, 0x83, + 0x7f, 0x81, 0x7f, 0x7f, 0x81, 0x81, 0x7f, 0x81, 0x84, 0x80, 0x86, + 0x73, 0x7c, 0x84, 0x6f, 0x7b, 0x77, 0x70, 0x82, 0x72, 0x70, 0x86, + 0x75, 0x7f, 0x7e, 0x77, 0x89, 0x81, 0x7e, 0x87, 0x87, 0x8b, 0x89, + 0x86, 0x8d, 0x8b, 0x88, 0x84, 0x85, 0x85, 0x82, 0x7f, 0x7a, 0x83, + 0x7d, 0x7b, 0x7e, 0x7a, 0x7d, 0x79, 0x77, 0x7b, 0x7b, 0x79, 0x7c, + 0x7f, 0x81, 0x81, 0x82, 0x83, 0x87, 0x86, 0x81, 0x87, 0x85, 0x81, + 0x84, 0x82, 0x7f, 0x85, 0x7f, 0x7e, 0x81, 0x71, 0x7e, 0x7b, 0x6c, + 0x7d, 0x70, 0x73, 0x7d, 0x68, 0x78, 0x7b, 0x70, 0x81, 0x75, 0x7d, + 0x8a, 0x7d, 0x89, 0x8b, 0x8c, 0x93, 0x8d, 0x8f, 0x92, 0x8f, 0x8a, + 0x86, 0x87, 0x83, 0x80, 0x7c, 0x7b, 0x7e, 0x78, 0x77, 0x78, 0x78, + 0x78, 0x76, 0x76, 0x7a, 0x79, 0x7b, 0x7f, 0x7f, 0x85, 0x82, 0x84, + 0x88, 0x84, 0x87, 0x88, 0x89, 0x87, 0x8a, 0x85, 0x86, 0x87, 0x7e, + 0x85, 0x73, 0x76, 0x81, 0x67, 0x70, 0x72, 0x62, 0x76, 0x68, 0x63, + 0x7e, 0x6b, 0x76, 0x7e, 0x76, 0x8d, 0x85, 0x85, 0x93, 0x90, 0x96, + 0x93, 0x92, 0x98, 0x94, 0x92, 0x8d, 0x8d, 0x8d, 0x82, 0x83, 0x7c, + 0x7b, 0x7a, 0x6e, 0x72, 0x72, 0x6d, 0x6e, 0x6d, 0x71, 0x75, 0x75, + 0x7a, 0x83, 0x84, 0x8b, 0x8e, 0x8e, 0x94, 0x8d, 0x8c, 0x8e, 0x8b, + 0x87, 0x85, 0x83, 0x80, 0x81, 0x70, 0x71, 0x7f, 0x66, 0x6c, 0x71, + 0x5e, 0x75, 0x67, 0x5e, 0x7e, 0x6c, 0x74, 0x80, 0x76, 0x90, 0x8a, + 0x85, 0x97, 0x95, 0x99, 0x98, 0x94, 0x9c, 0x99, 0x95, 0x8e, 0x91, + 0x92, 0x83, 0x82, 0x7b, 0x7a, 0x76, 0x67, 0x6e, 0x6e, 0x6a, 0x6a, + 0x6b, 0x73, 0x76, 0x76, 0x7b, 0x89, 0x89, 0x8b, 0x90, 0x93, 0x96, + 0x8f, 0x90, 0x8f, 0x8d, 0x87, 0x84, 0x83, 0x81, 0x76, 0x6b, 0x7e, + 0x6c, 0x63, 0x71, 0x5c, 0x6d, 0x6c, 0x56, 0x71, 0x70, 0x6d, 0x7c, + 0x76, 0x87, 0x92, 0x87, 0x95, 0x9a, 0x9f, 0x9e, 0x9a, 0xa2, 0x9e, + 0x9d, 0x94, 0x8f, 0x96, 0x87, 0x7e, 0x7d, 0x7a, 0x74, 0x69, 0x69, + 0x6b, 0x6b, 0x66, 0x69, 0x72, 0x74, 0x76, 0x7b, 0x87, 0x8a, 0x8c, + 0x90, 0x95, 0x97, 0x93, 0x92, 0x92, 0x91, 0x8a, 0x86, 0x84, 0x83, + 0x75, 0x68, 0x7c, 0x69, 0x5e, 0x6f, 0x56, 0x67, 0x6a, 0x53, 0x6f, + 0x71, 0x6b, 0x7c, 0x7a, 0x8a, 0x95, 0x8f, 0x99, 0xa1, 0xa8, 0xa2, + 0x9e, 0xa8, 0x9e, 0x9d, 0x96, 0x8a, 0x92, 0x83, 0x74, 0x79, 0x70, + 0x67, 0x66, 0x61, 0x63, 0x68, 0x64, 0x6b, 0x78, 0x78, 0x7e, 0x8a, + 0x90, 0x95, 0x98, 0x98, 0x9d, 0x9c, 0x95, 0x95, 0x94, 0x8b, 0x85, + 0x82, 0x7b, 0x7b, 0x66, 0x5f, 0x72, 0x55, 0x54, 0x64, 0x50, 0x63, + 0x61, 0x59, 0x75, 0x75, 0x7a, 0x85, 0x8f, 0x9e, 0x9b, 0xa2, 0xa9, + 0xa9, 0xb3, 0xa2, 0xa1, 0xab, 0x96, 0x91, 0x8a, 0x7f, 0x81, 0x70, + 0x65, 0x67, 0x67, 0x5b, 0x58, 0x64, 0x65, 0x67, 0x6e, 0x78, 0x84, + 0x88, 0x8b, 0x95, 0x9f, 0x9c, 0x9e, 0xa2, 0xa0, 0x9b, 0x92, 0x90, + 0x8c, 0x85, 0x7d, 0x7b, 0x78, 0x73, 0x70, 0x55, 0x60, 0x6f, 0x48, + 0x53, 0x63, 0x51, 0x62, 0x61, 0x62, 0x7c, 0x81, 0x83, 0x8b, 0xa2, + 0xa9, 0x9c, 0xae, 0xb1, 0xab, 0xb2, 0x9f, 0x9e, 0xa3, 0x8d, 0x83, + 0x7e, 0x7b, 0x72, 0x64, 0x65, 0x62, 0x63, 0x5d, 0x5a, 0x69, 0x6e, + 0x6c, 0x74, 0x83, 0x88, 0x8a, 0x91, 0x98, 0x9f, 0x9d, 0x9b, 0x9e, + 0x9e, 0x94, 0x8e, 0x8f, 0x89, 0x81, 0x7e, 0x7c, 0x79, 0x75, 0x74, + 0x6b, 0x56, 0x67, 0x68, 0x44, 0x5a, 0x62, 0x51, 0x5f, 0x63, 0x6c, + 0x7a, 0x84, 0x8b, 0x91, 0xab, 0xab, 0x9e, 0xb4, 0xb4, 0xa9, 0xad, + 0xa1, 0x9c, 0x95, 0x88, 0x7f, 0x76, 0x7a, 0x6e, 0x61, 0x6a, 0x65, + 0x60, 0x64, 0x63, 0x67, 0x70, 0x71, 0x72, 0x80, 0x88, 0x87, 0x8e, + 0x98, 0x9a, 0x99, 0x9d, 0x9c, 0x9b, 0x99, 0x90, 0x8d, 0x8b, 0x84, + 0x7d, 0x7f, 0x7c, 0x77, 0x75, 0x75, 0x6f, 0x58, 0x60, 0x68, 0x4c, + 0x52, 0x5f, 0x56, 0x5b, 0x63, 0x6e, 0x76, 0x84, 0x93, 0x91, 0xa5, + 0xb2, 0xa5, 0xad, 0xb4, 0xaf, 0xaa, 0xa0, 0x9c, 0x91, 0x88, 0x83, + 0x74, 0x75, 0x72, 0x65, 0x65, 0x66, 0x67, 0x62, 0x63, 0x6a, 0x6a, + 0x6d, 0x71, 0x77, 0x80, 0x86, 0x89, 0x8f, 0x97, 0x99, 0x9a, 0x9b, + 0x9d, 0x9a, 0x96, 0x93, 0x8d, 0x89, 0x83, 0x7e, 0x7c, 0x7a, 0x76, + 0x73, 0x73, 0x73, 0x72, 0x61, 0x58, 0x65, 0x5d, 0x50, 0x59, 0x5f, + 0x61, 0x61, 0x6b, 0x79, 0x7f, 0x8e, 0x97, 0x9d, 0xaa, 0xac, 0xab, + 0xab, 0xad, 0xaf, 0xa0, 0x97, 0x93, 0x89, 0x82, 0x78, 0x72, 0x71, + 0x6b, 0x67, 0x63, 0x64, 0x6a, 0x69, 0x68, 0x6a, 0x6f, 0x72, 0x74, + 0x7a, 0x82, 0x87, 0x8b, 0x8e, 0x92, 0x97, 0x97, 0x97, 0x95, 0x94, + 0x92, 0x8c, 0x88, 0x85, 0x82, 0x7c, 0x77, 0x76, 0x74, 0x73, 0x73, + 0x73, 0x74, 0x75, 0x74, 0x6b, 0x66, 0x6b, 0x6b, 0x65, 0x62, 0x67, + 0x6d, 0x6b, 0x71, 0x7c, 0x81, 0x89, 0x94, 0x99, 0x99, 0x9c, 0xa1, + 0x9d, 0x9a, 0x9c, 0x96, 0x8e, 0x8a, 0x87, 0x82, 0x7d, 0x7d, 0x79, + 0x74, 0x74, 0x73, 0x72, 0x74, 0x75, 0x75, 0x76, 0x76, 0x77, 0x78, + 0x78, 0x79, 0x7b, 0x7e, 0x7f, 0x81, 0x84, 0x86, 0x88, 0x89, 0x89, + 0x88, 0x87, 0x88, 0x85, 0x83, 0x82, 0x81, 0x7f, 0x7f, 0x7e, 0x7f, + 0x80, 0x82, 0x82, 0x82, 0x83, 0x82, 0x81, 0x7a, 0x6f, 0x6c, 0x6f, + 0x68, 0x60, 0x65, 0x68, 0x64, 0x69, 0x72, 0x74, 0x77, 0x83, 0x8a, + 0x88, 0x8e, 0x95, 0x96, 0x99, 0x9c, 0x9b, 0x96, 0x95, 0x94, 0x90, + 0x8d, 0x8a, 0x86, 0x85, 0x81, 0x7d, 0x7c, 0x79, 0x73, 0x71, 0x71, + 0x6d, 0x6a, 0x6c, 0x6d, 0x6c, 0x6f, 0x72, 0x74, 0x77, 0x7c, 0x80, + 0x82, 0x85, 0x88, 0x8b, 0x8d, 0x8e, 0x8f, 0x8f, 0x8e, 0x8e, 0x8d, + 0x8b, 0x89, 0x87, 0x85, 0x82, 0x80, 0x7f, 0x7c, 0x7a, 0x79, 0x78, + 0x78, 0x75, 0x6f, 0x69, 0x6c, 0x6d, 0x64, 0x65, 0x6b, 0x68, 0x69, + 0x73, 0x78, 0x79, 0x82, 0x8a, 0x88, 0x8d, 0x94, 0x95, 0x96, 0x99, + 0x99, 0x98, 0x96, 0x93, 0x90, 0x8f, 0x8b, 0x86, 0x85, 0x81, 0x7c, + 0x7b, 0x7a, 0x76, 0x73, 0x74, 0x72, 0x6f, 0x71, 0x71, 0x70, 0x70, + 0x73, 0x73, 0x74, 0x78, 0x7b, 0x7d, 0x7f, 0x82, 0x84, 0x86, 0x88, + 0x89, 0x8a, 0x8a, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8a, 0x88, 0x87, + 0x87, 0x85, 0x83, 0x82, 0x81, 0x80, 0x7e, 0x7b, 0x78, 0x76, 0x70, + 0x66, 0x67, 0x68, 0x5f, 0x60, 0x66, 0x64, 0x65, 0x6f, 0x76, 0x78, + 0x82, 0x8b, 0x8c, 0x91, 0x98, 0x9a, 0x9c, 0x9d, 0x9c, 0x9c, 0x9a, + 0x95, 0x92, 0x90, 0x8a, 0x86, 0x84, 0x7f, 0x79, 0x76, 0x74, 0x70, + 0x6d, 0x6c, 0x6b, 0x6b, 0x6c, 0x6c, 0x6e, 0x70, 0x74, 0x77, 0x7a, + 0x7e, 0x83, 0x86, 0x87, 0x89, 0x8c, 0x8d, 0x8d, 0x8d, 0x8d, 0x8b, + 0x8a, 0x89, 0x86, 0x85, 0x83, 0x80, 0x7f, 0x7d, 0x7b, 0x7b, 0x7b, + 0x79, 0x7a, 0x7b, 0x7a, 0x7c, 0x7d, 0x7d, 0x7d, 0x7e, 0x7e, 0x7e, + 0x7c, 0x75, 0x75, 0x79, 0x72, 0x6f, 0x73, 0x73, 0x70, 0x75, 0x7a, + 0x7a, 0x7e, 0x84, 0x85, 0x87, 0x8b, 0x8d, 0x8f, 0x90, 0x8f, 0x90, + 0x90, 0x8c, 0x8b, 0x8c, 0x89, 0x85, 0x86, 0x84, 0x80, 0x7e, 0x7e, + 0x7c, 0x79, 0x78, 0x77, 0x75, 0x74, 0x75, 0x76, 0x74, 0x74, 0x78, + 0x78, 0x78, 0x7b, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x83, 0x84, 0x84, + 0x85, 0x85, 0x85, 0x87, 0x86, 0x86, 0x86, 0x86, 0x84, 0x84, 0x83, + 0x82, 0x81, 0x80, 0x7e, 0x7f, 0x7e, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, + 0x7e, 0x7e, 0x7c, 0x7b, 0x7b, 0x77, 0x70, 0x71, 0x73, 0x6f, 0x6d, + 0x72, 0x73, 0x74, 0x79, 0x7e, 0x81, 0x86, 0x8a, 0x8b, 0x8e, 0x8f, + 0x91, 0x92, 0x91, 0x8f, 0x8f, 0x8d, 0x89, 0x88, 0x87, 0x82, 0x80, + 0x7f, 0x7d, 0x7b, 0x79, 0x78, 0x77, 0x76, 0x75, 0x75, 0x76, 0x76, + 0x77, 0x78, 0x79, 0x7c, 0x7d, 0x7e, 0x81, 0x82, 0x83, 0x84, 0x85, + 0x84, 0x84, 0x84, 0x82, 0x81, 0x81, 0x80, 0x80, 0x7f, 0x7e, 0x7e, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x81, 0x80, 0x80, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x82, 0x82, 0x82, 0x82, 0x82, 0x81, + 0x80, 0x7e, 0x7c, 0x77, 0x74, 0x74, 0x71, 0x6f, 0x70, 0x70, 0x71, + 0x74, 0x78, 0x7c, 0x7f, 0x84, 0x87, 0x8a, 0x8c, 0x8e, 0x90, 0x90, + 0x90, 0x8f, 0x8e, 0x8c, 0x8a, 0x89, 0x87, 0x84, 0x82, 0x7f, 0x7e, + 0x7b, 0x79, 0x78, 0x76, 0x74, 0x73, 0x73, 0x73, 0x75, 0x76, 0x76, + 0x79, 0x7c, 0x7c, 0x7f, 0x81, 0x83, 0x85, 0x85, 0x85, 0x87, 0x86, + 0x86, 0x86, 0x84, 0x83, 0x83, 0x81, 0x80, 0x7f, 0x7e, 0x7d, 0x7c, + 0x7d, 0x7d, 0x7c, 0x7d, 0x7e, 0x7f, 0x7f, 0x80, 0x81, 0x81, 0x82, + 0x83, 0x84, 0x84, 0x83, 0x82, 0x82, 0x81, 0x7e, 0x7c, 0x77, 0x73, + 0x74, 0x71, 0x6e, 0x6f, 0x70, 0x71, 0x75, 0x79, 0x7c, 0x80, 0x85, + 0x88, 0x8b, 0x8c, 0x8e, 0x90, 0x8f, 0x8f, 0x8e, 0x8c, 0x8a, 0x88, + 0x87, 0x84, 0x82, 0x80, 0x7e, 0x7d, 0x7a, 0x79, 0x79, 0x77, 0x76, + 0x76, 0x76, 0x76, 0x78, 0x79, 0x79, 0x7b, 0x7e, 0x7f, 0x80, 0x81, + 0x82, 0x84, 0x84, 0x84, 0x85, 0x84, 0x84, 0x84, 0x81, 0x81, 0x81, + 0x80, 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, + 0x7f, 0x7f, 0x7f, 0x81, 0x82, 0x82, 0x82, 0x83, 0x84, 0x84, 0x83, + 0x83, 0x83, 0x82, 0x80, 0x7d, 0x7b, 0x79, 0x75, 0x73, 0x72, 0x70, + 0x6f, 0x6f, 0x71, 0x72, 0x75, 0x79, 0x7c, 0x81, 0x84, 0x87, 0x8a, + 0x8d, 0x8f, 0x91, 0x91, 0x91, 0x91, 0x90, 0x8e, 0x8c, 0x8a, 0x87, + 0x85, 0x82, 0x7f, 0x7c, 0x7a, 0x78, 0x77, 0x75, 0x75, 0x74, 0x74, + 0x74, 0x76, 0x77, 0x78, 0x7a, 0x7b, 0x7d, 0x80, 0x81, 0x83, 0x85, + 0x86, 0x86, 0x86, 0x86, 0x85, 0x85, 0x84, 0x83, 0x82, 0x81, 0x80, + 0x7f, 0x7e, 0x7d, 0x7e, 0x7d, 0x7e, 0x7e, 0x7e, 0x80, 0x80, 0x80, + 0x81, 0x81, 0x82, 0x82, 0x82, 0x81, 0x81, 0x81, 0x80, 0x7f, 0x7d, + 0x7b, 0x7b, 0x79, 0x75, 0x74, 0x74, 0x72, 0x71, 0x72, 0x74, 0x75, + 0x79, 0x7d, 0x80, 0x84, 0x87, 0x8b, 0x8e, 0x8f, 0x91, 0x92, 0x91, + 0x90, 0x8f, 0x8d, 0x8b, 0x88, 0x86, 0x82, 0x80, 0x7e, 0x7b, 0x7a, + 0x78, 0x77, 0x76, 0x75, 0x75, 0x76, 0x76, 0x77, 0x78, 0x79, 0x7a, + 0x7c, 0x7e, 0x7f, 0x81, 0x83, 0x84, 0x85, 0x86, 0x87, 0x86, 0x86, + 0x85, 0x84, 0x82, 0x81, 0x80, 0x7f, 0x7e, 0x7e, 0x7d, 0x7d, 0x7d, + 0x7d, 0x7d, 0x7e, 0x7e, 0x7e, 0x80, 0x80, 0x81, 0x82, 0x82, 0x82, + 0x83, 0x83, 0x82, 0x83, 0x82, 0x81, 0x81, 0x80, 0x80, 0x7e, 0x7c, + 0x7b, 0x78, 0x73, 0x72, 0x73, 0x70, 0x6e, 0x70, 0x72, 0x73, 0x77, + 0x7c, 0x7f, 0x83, 0x88, 0x8c, 0x8f, 0x90, 0x92, 0x94, 0x93, 0x92, + 0x91, 0x8f, 0x8d, 0x8a, 0x88, 0x85, 0x82, 0x7f, 0x7e, 0x7c, 0x79, + 0x78, 0x77, 0x75, 0x74, 0x74, 0x74, 0x74, 0x75, 0x76, 0x77, 0x78, + 0x7a, 0x7d, 0x7e, 0x80, 0x82, 0x84, 0x85, 0x85, 0x86, 0x86, 0x86, + 0x85, 0x85, 0x84, 0x83, 0x83, 0x82, 0x81, 0x81, 0x80, 0x80, 0x7f, + 0x7f, 0x7e, 0x7e, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7e, 0x7e, 0x7e, + 0x7e, 0x7e, 0x7f, 0x7e, 0x7e, 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, + 0x7d, 0x7d, 0x7e, 0x7e, 0x7c, 0x7a, 0x7a, 0x7b, 0x79, 0x79, 0x7a, + 0x7a, 0x7a, 0x7c, 0x7e, 0x7f, 0x81, 0x83, 0x86, 0x88, 0x89, 0x8b, + 0x8c, 0x8c, 0x8c, 0x8b, 0x8b, 0x89, 0x87, 0x86, 0x84, 0x82, 0x80, + 0x7f, 0x7d, 0x7b, 0x7a, 0x79, 0x78, 0x77, 0x77, 0x77, 0x78, 0x79, + 0x79, 0x7b, 0x7c, 0x7e, 0x80, 0x81, 0x82, 0x83, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x83, 0x82, 0x81, 0x81, 0x7f, 0x7f, 0x7e, 0x7d, 0x7c, + 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7d, 0x7d, 0x7e, 0x7e, 0x7f, + 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x7d, + 0x7d, 0x7d, 0x7d, 0x7d, 0x7e, 0x7e, 0x7f, 0x7f, 0x80, 0x81, 0x81, + 0x82, 0x83, 0x83, 0x84, 0x84, 0x84, 0x84, 0x84, 0x83, 0x83, 0x83, + 0x82, 0x81, 0x80, 0x80, 0x7f, 0x7e, 0x7e, 0x7d, 0x7d, 0x7d, 0x7d, + 0x7d, 0x7d, 0x7d, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x80, 0x80, 0x80, + 0x80, 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, + 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, + }, + { // 2 + 0x80, 0x7f, 0x80, 0x7f, 0x7e, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, + 0x80, 0x7f, 0x7f, 0x7d, 0x7c, 0x80, 0x81, 0x7e, 0x7c, 0x7c, 0x7f, + 0x83, 0x85, 0x86, 0x88, 0x88, 0x85, 0x81, 0x7e, 0x7d, 0x7d, 0x7c, + 0x7a, 0x7a, 0x7b, 0x7c, 0x7e, 0x7f, 0x80, 0x81, 0x81, 0x81, 0x80, + 0x82, 0x81, 0x80, 0x7f, 0x7e, 0x7e, 0x7e, 0x7f, 0x7e, 0x7e, 0x7f, + 0x7f, 0x80, 0x80, 0x80, 0x80, 0x81, 0x82, 0x81, 0x80, 0x80, 0x80, + 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x7d, 0x7e, 0x7e, 0x7f, 0x80, 0x80, + 0x80, 0x81, 0x81, 0x82, 0x81, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x7e, + 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x81, 0x82, 0x82, 0x80, 0x7f, 0x81, + 0x82, 0x81, 0x7f, 0x7e, 0x7f, 0x81, 0x80, 0x7f, 0x7e, 0x7f, 0x80, + 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x80, + 0x80, 0x81, 0x82, 0x81, 0x81, 0x80, 0x80, 0x7f, 0x7e, 0x7c, 0x7b, + 0x7b, 0x79, 0x78, 0x6d, 0x69, 0x76, 0x76, 0x75, 0x7b, 0x7d, 0x85, + 0x8c, 0x94, 0x92, 0x8d, 0x95, 0x95, 0x8d, 0x89, 0x81, 0x7a, 0x78, + 0x76, 0x75, 0x6f, 0x71, 0x75, 0x78, 0x80, 0x82, 0x85, 0x89, 0x8e, + 0x8e, 0x8a, 0x89, 0x84, 0x81, 0x7e, 0x7a, 0x77, 0x77, 0x7a, 0x7a, + 0x7d, 0x80, 0x82, 0x86, 0x88, 0x8a, 0x87, 0x86, 0x87, 0x84, 0x82, + 0x80, 0x7e, 0x7e, 0x7f, 0x7e, 0x57, 0x2e, 0x5c, 0x6e, 0x54, 0x65, + 0x64, 0x6e, 0x8c, 0xac, 0xb6, 0x94, 0xa1, 0xbf, 0xac, 0x9d, 0x94, + 0x75, 0x65, 0x71, 0x74, 0x60, 0x4d, 0x66, 0x78, 0x7a, 0x95, 0x94, + 0x8a, 0x97, 0xa8, 0xa5, 0x8c, 0x84, 0x7c, 0x6c, 0x6b, 0x65, 0x57, + 0x55, 0x67, 0x75, 0x7b, 0x88, 0x90, 0x93, 0x9e, 0xa3, 0x98, 0x8d, + 0x89, 0x81, 0x79, 0x77, 0x6f, 0x68, 0x6e, 0x78, 0x79, 0x7e, 0x86, + 0x8a, 0x8e, 0x96, 0x95, 0x8f, 0x8d, 0x8b, 0x6a, 0x32, 0x44, 0x5e, + 0x45, 0x56, 0x5e, 0x5a, 0x76, 0x9a, 0xc0, 0xaf, 0xa5, 0xbf, 0xb4, + 0xa8, 0xa9, 0x8b, 0x64, 0x5b, 0x64, 0x66, 0x53, 0x55, 0x68, 0x65, + 0x85, 0xa5, 0x9b, 0x9a, 0x9c, 0xa7, 0xa4, 0x94, 0x8d, 0x6c, 0x59, + 0x61, 0x5c, 0x56, 0x55, 0x61, 0x6c, 0x82, 0x9f, 0x9d, 0x99, 0xa0, + 0xa0, 0x9b, 0x95, 0x8b, 0x73, 0x6c, 0x71, 0x6d, 0x6c, 0x6d, 0x6f, + 0x74, 0x82, 0x92, 0x91, 0x93, 0x97, 0x93, 0x93, 0x90, 0x84, 0x53, + 0x2b, 0x4d, 0x52, 0x49, 0x63, 0x5b, 0x5e, 0x7b, 0xa5, 0xc4, 0xb0, + 0xb0, 0xba, 0xa4, 0xa4, 0xa9, 0x87, 0x62, 0x56, 0x5a, 0x5f, 0x59, + 0x67, 0x6c, 0x61, 0x86, 0xa2, 0xa3, 0xa6, 0x9f, 0x9d, 0x93, 0x8f, + 0x94, 0x71, 0x58, 0x56, 0x4e, 0x55, 0x63, 0x70, 0x6e, 0x7a, 0x97, + 0x9c, 0xa4, 0xa8, 0x99, 0x8c, 0x8a, 0x8a, 0x7c, 0x72, 0x6e, 0x62, + 0x67, 0x75, 0x7b, 0x7c, 0x82, 0x8a, 0x8c, 0x97, 0x9f, 0x95, 0x8f, + 0x86, 0x7b, 0x54, 0x35, 0x4e, 0x47, 0x45, 0x65, 0x62, 0x67, 0x7c, + 0x9c, 0xb9, 0xb3, 0xbc, 0xbc, 0x9e, 0x98, 0x9d, 0x87, 0x6e, 0x62, + 0x58, 0x53, 0x54, 0x6b, 0x79, 0x6f, 0x87, 0x97, 0x95, 0xa5, 0xa8, + 0xa2, 0x91, 0x85, 0x85, 0x71, 0x63, 0x64, 0x54, 0x4b, 0x58, 0x68, + 0x73, 0x84, 0x97, 0x95, 0x96, 0xa4, 0x9e, 0x94, 0x90, 0x85, 0x75, + 0x72, 0x76, 0x6e, 0x6d, 0x75, 0x73, 0x77, 0x85, 0x8c, 0x8d, 0x91, + 0x96, 0x8f, 0x8d, 0x8b, 0x80, 0x62, 0x3b, 0x42, 0x48, 0x42, 0x64, + 0x6c, 0x66, 0x77, 0x89, 0xa7, 0xb4, 0xbf, 0xc7, 0xa9, 0x95, 0x95, + 0x86, 0x78, 0x74, 0x66, 0x54, 0x4f, 0x5b, 0x6f, 0x77, 0x8a, 0x9a, + 0x8d, 0x94, 0xa0, 0x9d, 0x9e, 0x96, 0x8a, 0x74, 0x60, 0x62, 0x5b, + 0x59, 0x61, 0x60, 0x66, 0x75, 0x8a, 0x97, 0x9c, 0xa3, 0x99, 0x8f, + 0x90, 0x89, 0x83, 0x7f, 0x77, 0x6e, 0x6b, 0x73, 0x77, 0x7d, 0x86, + 0x85, 0x87, 0x8c, 0x91, 0x93, 0x93, 0x8d, 0x80, 0x67, 0x42, 0x40, + 0x48, 0x43, 0x60, 0x6d, 0x68, 0x77, 0x83, 0x9d, 0xb0, 0xbc, 0xc8, + 0xb1, 0x9a, 0x95, 0x84, 0x78, 0x79, 0x6f, 0x5e, 0x56, 0x58, 0x64, + 0x70, 0x86, 0x9b, 0x94, 0x96, 0x9d, 0x92, 0x96, 0x98, 0x8f, 0x80, + 0x6b, 0x62, 0x57, 0x53, 0x62, 0x65, 0x6b, 0x79, 0x80, 0x8a, 0x97, + 0xa3, 0xa3, 0x99, 0x94, 0x86, 0x7d, 0x80, 0x7b, 0x78, 0x76, 0x72, + 0x71, 0x78, 0x82, 0x87, 0x8b, 0x8f, 0x8d, 0x8d, 0x8f, 0x8b, 0x84, + 0x71, 0x4d, 0x41, 0x42, 0x3d, 0x58, 0x6f, 0x73, 0x80, 0x86, 0x92, + 0xa3, 0xb1, 0xc5, 0xbe, 0xa8, 0x9b, 0x81, 0x6e, 0x70, 0x70, 0x69, + 0x67, 0x62, 0x60, 0x66, 0x78, 0x91, 0x9a, 0xa0, 0xa4, 0x93, 0x8c, + 0x8e, 0x86, 0x83, 0x7d, 0x71, 0x61, 0x54, 0x58, 0x5c, 0x69, 0x80, + 0x89, 0x8f, 0x96, 0x94, 0x96, 0x97, 0x97, 0x8f, 0x85, 0x7f, 0x74, + 0x72, 0x77, 0x77, 0x7c, 0x80, 0x7f, 0x81, 0x85, 0x8b, 0x8f, 0x92, + 0x93, 0x8a, 0x7b, 0x5f, 0x44, 0x44, 0x41, 0x4a, 0x69, 0x70, 0x78, + 0x86, 0x8a, 0x98, 0xa6, 0xb6, 0xbe, 0xb2, 0xa6, 0x92, 0x75, 0x6a, + 0x6c, 0x67, 0x69, 0x6f, 0x67, 0x67, 0x70, 0x7f, 0x8f, 0x9b, 0xa7, + 0xa2, 0x93, 0x90, 0x85, 0x7a, 0x7c, 0x77, 0x6d, 0x66, 0x5f, 0x59, + 0x5d, 0x6c, 0x7d, 0x8b, 0x9b, 0x9c, 0x97, 0x95, 0x8f, 0x8a, 0x8a, + 0x86, 0x7f, 0x79, 0x76, 0x73, 0x75, 0x7f, 0x83, 0x86, 0x8b, 0x8a, + 0x8a, 0x8e, 0x8f, 0x8c, 0x82, 0x68, 0x4c, 0x43, 0x3c, 0x41, 0x60, + 0x71, 0x7c, 0x8d, 0x8f, 0x94, 0x9d, 0xab, 0xb6, 0xb2, 0xae, 0x9f, + 0x80, 0x6e, 0x66, 0x5e, 0x63, 0x71, 0x72, 0x72, 0x78, 0x7a, 0x83, + 0x90, 0x9f, 0xa4, 0x9e, 0x9b, 0x8c, 0x79, 0x76, 0x6e, 0x67, 0x6a, + 0x67, 0x61, 0x63, 0x6a, 0x72, 0x81, 0x95, 0x9e, 0x9f, 0x9e, 0x93, + 0x88, 0x85, 0x81, 0x7e, 0x80, 0x7f, 0x7b, 0x79, 0x7b, 0x7c, 0x81, + 0x8a, 0x8e, 0x91, 0x93, 0x8d, 0x84, 0x71, 0x53, 0x49, 0x44, 0x3f, + 0x57, 0x6b, 0x74, 0x89, 0x90, 0x92, 0x9c, 0xa4, 0xae, 0xb0, 0xab, + 0xa3, 0x8c, 0x76, 0x6b, 0x60, 0x5e, 0x6a, 0x6f, 0x72, 0x7d, 0x7f, + 0x83, 0x8d, 0x95, 0x9c, 0x9e, 0x9d, 0x96, 0x84, 0x78, 0x6f, 0x62, + 0x62, 0x64, 0x63, 0x68, 0x6f, 0x78, 0x83, 0x90, 0x9b, 0x9f, 0x9e, + 0x97, 0x8b, 0x84, 0x7d, 0x78, 0x7c, 0x7e, 0x7d, 0x7f, 0x7d, 0x7c, + 0x80, 0x86, 0x8d, 0x92, 0x93, 0x8d, 0x7a, 0x5b, 0x4c, 0x43, 0x3c, + 0x54, 0x6b, 0x74, 0x8c, 0x95, 0x92, 0x9a, 0x9f, 0xa5, 0xaa, 0xac, + 0xa6, 0x91, 0x7c, 0x6c, 0x5b, 0x56, 0x62, 0x6a, 0x72, 0x83, 0x86, + 0x85, 0x8e, 0x91, 0x94, 0x9b, 0x9d, 0x9a, 0x8e, 0x82, 0x72, 0x5f, + 0x59, 0x5a, 0x5c, 0x68, 0x75, 0x7f, 0x8a, 0x93, 0x99, 0x9c, 0x9d, + 0x9a, 0x91, 0x89, 0x80, 0x78, 0x76, 0x76, 0x77, 0x7a, 0x7c, 0x7d, + 0x81, 0x85, 0x8b, 0x8d, 0x8c, 0x7d, 0x63, 0x58, 0x4c, 0x43, 0x58, + 0x69, 0x75, 0x8d, 0x96, 0x94, 0x99, 0x9d, 0xa0, 0xa4, 0xa8, 0xa3, + 0x93, 0x82, 0x70, 0x5d, 0x55, 0x5d, 0x62, 0x6c, 0x7e, 0x84, 0x89, + 0x92, 0x92, 0x93, 0x98, 0x9b, 0x98, 0x91, 0x86, 0x75, 0x64, 0x5b, + 0x57, 0x59, 0x67, 0x77, 0x84, 0x90, 0x97, 0x98, 0x9a, 0x98, 0x94, + 0x90, 0x8c, 0x85, 0x7f, 0x7a, 0x75, 0x71, 0x73, 0x74, 0x78, 0x81, + 0x88, 0x8a, 0x83, 0x6d, 0x5e, 0x55, 0x4b, 0x5b, 0x6e, 0x77, 0x8e, + 0x96, 0x90, 0x94, 0x95, 0x95, 0x9c, 0xa1, 0xa0, 0x97, 0x88, 0x79, + 0x69, 0x5e, 0x62, 0x65, 0x6b, 0x7c, 0x82, 0x83, 0x8b, 0x8a, 0x89, + 0x8f, 0x92, 0x93, 0x91, 0x8a, 0x7e, 0x6e, 0x64, 0x5f, 0x5f, 0x6b, + 0x79, 0x84, 0x91, 0x93, 0x91, 0x92, 0x8f, 0x8e, 0x8e, 0x8c, 0x89, + 0x85, 0x80, 0x7b, 0x77, 0x76, 0x75, 0x79, 0x7e, 0x7f, 0x77, 0x61, + 0x58, 0x52, 0x49, 0x60, 0x77, 0x81, 0x9c, 0xa4, 0x99, 0x9a, 0x97, + 0x91, 0x94, 0x99, 0x95, 0x8a, 0x7d, 0x6e, 0x60, 0x5b, 0x67, 0x70, + 0x7a, 0x8e, 0x91, 0x8e, 0x93, 0x8b, 0x85, 0x89, 0x88, 0x86, 0x81, + 0x7a, 0x6d, 0x61, 0x60, 0x61, 0x6a, 0x7e, 0x8c, 0x96, 0x9e, 0x9a, + 0x92, 0x8e, 0x88, 0x86, 0x85, 0x84, 0x82, 0x7d, 0x7a, 0x77, 0x76, + 0x7b, 0x80, 0x84, 0x85, 0x7a, 0x5e, 0x52, 0x4c, 0x42, 0x5e, 0x79, + 0x83, 0x9d, 0xa5, 0x99, 0x9a, 0x99, 0x97, 0x98, 0x9a, 0x94, 0x82, + 0x6f, 0x62, 0x55, 0x55, 0x6b, 0x7a, 0x84, 0x98, 0x96, 0x8e, 0x90, + 0x8b, 0x88, 0x8c, 0x8c, 0x86, 0x7a, 0x6e, 0x60, 0x57, 0x5e, 0x69, + 0x76, 0x8a, 0x93, 0x94, 0x96, 0x90, 0x8b, 0x8c, 0x8b, 0x8a, 0x86, + 0x84, 0x7f, 0x79, 0x7a, 0x7b, 0x7b, 0x82, 0x84, 0x82, 0x7b, 0x5d, + 0x49, 0x4a, 0x41, 0x59, 0x81, 0x89, 0x9d, 0xa9, 0x9a, 0x98, 0x9b, + 0x99, 0x9b, 0x97, 0x8b, 0x76, 0x5e, 0x55, 0x55, 0x5c, 0x78, 0x8f, + 0x93, 0x9e, 0x9b, 0x8c, 0x8e, 0x8c, 0x86, 0x86, 0x7e, 0x71, 0x63, + 0x5b, 0x5a, 0x5d, 0x71, 0x85, 0x8e, 0x9c, 0x9e, 0x97, 0x94, 0x8e, + 0x88, 0x84, 0x7d, 0x78, 0x73, 0x75, 0x7b, 0x7c, 0x83, 0x87, 0x86, + 0x8c, 0x8c, 0x87, 0x7b, 0x56, 0x45, 0x44, 0x38, 0x5a, 0x82, 0x87, + 0xa0, 0xa9, 0x99, 0x9d, 0xa2, 0x9f, 0x9c, 0x91, 0x7e, 0x63, 0x50, + 0x54, 0x5f, 0x6e, 0x90, 0x9c, 0x94, 0x9b, 0x93, 0x88, 0x91, 0x8e, + 0x82, 0x76, 0x68, 0x5b, 0x58, 0x66, 0x74, 0x7e, 0x8e, 0x8d, 0x87, + 0x8a, 0x88, 0x87, 0x8b, 0x88, 0x81, 0x7c, 0x7c, 0x7d, 0x83, 0x90, + 0x92, 0x8d, 0x8a, 0x82, 0x7c, 0x80, 0x7e, 0x79, 0x5f, 0x37, 0x37, + 0x3d, 0x4b, 0x8c, 0xa9, 0xa8, 0xb7, 0xa4, 0x90, 0x99, 0x9a, 0x93, + 0x81, 0x68, 0x4f, 0x3d, 0x4c, 0x73, 0x8e, 0xa8, 0xbb, 0xa5, 0x95, + 0x97, 0x8a, 0x89, 0x89, 0x70, 0x55, 0x44, 0x4a, 0x5e, 0x7e, 0xa0, + 0xa1, 0x96, 0x8d, 0x7c, 0x7d, 0x89, 0x87, 0x80, 0x75, 0x6b, 0x6a, + 0x78, 0x8b, 0x92, 0x92, 0x8e, 0x84, 0x86, 0x8d, 0x8e, 0x8f, 0x87, + 0x78, 0x6b, 0x61, 0x47, 0x3c, 0x57, 0x5e, 0x73, 0x9f, 0x9c, 0x9a, + 0xa3, 0x97, 0x92, 0x90, 0x89, 0x74, 0x5f, 0x5e, 0x60, 0x69, 0x88, + 0x9e, 0x9b, 0xa1, 0x9f, 0x89, 0x87, 0x86, 0x75, 0x6c, 0x64, 0x5e, + 0x60, 0x77, 0x92, 0x99, 0x9f, 0x97, 0x7e, 0x77, 0x75, 0x70, 0x72, + 0x74, 0x71, 0x72, 0x80, 0x8c, 0x90, 0x94, 0x8c, 0x80, 0x7f, 0x83, + 0x8a, 0x90, 0x8a, 0x7d, 0x75, 0x75, 0x7b, 0x80, 0x82, 0x65, 0x36, + 0x41, 0x59, 0x6b, 0xa8, 0xb7, 0x97, 0x94, 0x8d, 0x87, 0x92, 0x92, + 0x7b, 0x55, 0x4c, 0x5d, 0x70, 0x95, 0xb2, 0xa0, 0x8f, 0x92, 0x85, + 0x84, 0x8d, 0x79, 0x62, 0x5c, 0x63, 0x71, 0x8a, 0x9f, 0x97, 0x8c, + 0x88, 0x79, 0x73, 0x76, 0x6f, 0x68, 0x70, 0x7e, 0x88, 0x93, 0x97, + 0x88, 0x7e, 0x7d, 0x79, 0x7b, 0x81, 0x7f, 0x7f, 0x88, 0x8d, 0x89, + 0x87, 0x86, 0x82, 0x83, 0x80, 0x77, 0x58, 0x32, 0x42, 0x65, 0x79, + 0xab, 0xb2, 0x90, 0x92, 0x90, 0x88, 0x8a, 0x7c, 0x64, 0x52, 0x61, + 0x83, 0x96, 0xa5, 0xa7, 0x8b, 0x80, 0x89, 0x7f, 0x76, 0x71, 0x60, + 0x60, 0x77, 0x91, 0x9d, 0x98, 0x94, 0x84, 0x79, 0x81, 0x77, 0x65, + 0x61, 0x63, 0x71, 0x89, 0x9b, 0x96, 0x8a, 0x87, 0x7f, 0x7f, 0x84, + 0x7a, 0x72, 0x77, 0x7e, 0x86, 0x8c, 0x8a, 0x83, 0x85, 0x8b, 0x8b, + 0x87, 0x80, 0x73, 0x6b, 0x6e, 0x60, 0x43, 0x57, 0x77, 0x7f, 0xa6, + 0xac, 0x88, 0x87, 0x84, 0x79, 0x79, 0x74, 0x6b, 0x66, 0x7d, 0x9c, + 0xa1, 0xa1, 0x9b, 0x7f, 0x75, 0x7e, 0x73, 0x6c, 0x70, 0x70, 0x7b, + 0x90, 0x9a, 0x94, 0x83, 0x7a, 0x77, 0x75, 0x78, 0x78, 0x71, 0x77, + 0x83, 0x87, 0x8a, 0x86, 0x79, 0x74, 0x7a, 0x80, 0x80, 0x82, 0x80, + 0x7f, 0x87, 0x8a, 0x86, 0x82, 0x7c, 0x7c, 0x80, 0x85, 0x85, 0x81, + 0x7f, 0x7f, 0x82, 0x88, 0x87, 0x80, 0x79, 0x6b, 0x4c, 0x41, 0x65, + 0x7b, 0x8d, 0xa8, 0x92, 0x83, 0x8f, 0x87, 0x81, 0x7a, 0x6f, 0x6d, + 0x7b, 0x94, 0x9b, 0x91, 0x8c, 0x80, 0x76, 0x7e, 0x7a, 0x6e, 0x73, + 0x7c, 0x87, 0x96, 0x96, 0x89, 0x7b, 0x74, 0x76, 0x76, 0x75, 0x74, + 0x76, 0x7e, 0x8a, 0x8c, 0x84, 0x7d, 0x78, 0x7b, 0x83, 0x86, 0x82, + 0x7f, 0x7f, 0x7d, 0x7d, 0x7c, 0x78, 0x7a, 0x81, 0x88, 0x8c, 0x8a, + 0x84, 0x7c, 0x79, 0x7c, 0x7e, 0x83, 0x87, 0x88, 0x8a, 0x88, 0x82, + 0x7b, 0x72, 0x6e, 0x66, 0x4e, 0x4c, 0x74, 0x8b, 0x9b, 0xaa, 0x8c, + 0x78, 0x7f, 0x77, 0x75, 0x74, 0x70, 0x79, 0x8c, 0xa0, 0x9e, 0x8d, + 0x82, 0x77, 0x75, 0x7d, 0x79, 0x73, 0x7c, 0x88, 0x92, 0x98, 0x8a, + 0x77, 0x6d, 0x6f, 0x7a, 0x7d, 0x7e, 0x81, 0x81, 0x88, 0x8a, 0x7d, + 0x77, 0x74, 0x74, 0x7f, 0x83, 0x82, 0x80, 0x7b, 0x79, 0x76, 0x77, + 0x7c, 0x80, 0x89, 0x8c, 0x8b, 0x8a, 0x81, 0x7c, 0x7b, 0x7c, 0x81, + 0x83, 0x84, 0x84, 0x83, 0x82, 0x80, 0x7f, 0x80, 0x81, 0x84, 0x84, + 0x81, 0x7a, 0x70, 0x68, 0x63, 0x5e, 0x5a, 0x68, 0x83, 0x8f, 0x98, + 0x99, 0x87, 0x82, 0x82, 0x79, 0x76, 0x77, 0x7f, 0x8a, 0x94, 0x98, + 0x8c, 0x81, 0x7d, 0x79, 0x79, 0x7c, 0x7a, 0x7d, 0x88, 0x8d, 0x8b, + 0x84, 0x77, 0x6f, 0x70, 0x77, 0x7e, 0x80, 0x83, 0x85, 0x85, 0x86, + 0x81, 0x7a, 0x78, 0x75, 0x78, 0x82, 0x86, 0x84, 0x83, 0x7d, 0x79, + 0x7a, 0x7a, 0x7b, 0x81, 0x88, 0x89, 0x85, 0x7f, 0x77, 0x75, 0x79, + 0x7d, 0x83, 0x87, 0x87, 0x85, 0x80, 0x7d, 0x7b, 0x7d, 0x80, 0x81, + 0x83, 0x85, 0x84, 0x85, 0x84, 0x81, 0x7f, 0x7d, 0x78, 0x71, 0x6a, + 0x64, 0x5f, 0x61, 0x7b, 0x8d, 0x8e, 0x93, 0x88, 0x7a, 0x80, 0x7d, + 0x76, 0x78, 0x7e, 0x88, 0x91, 0x97, 0x91, 0x82, 0x7d, 0x7d, 0x7b, + 0x7f, 0x80, 0x80, 0x87, 0x8d, 0x89, 0x83, 0x7b, 0x74, 0x75, 0x79, + 0x7d, 0x7f, 0x7f, 0x82, 0x81, 0x7f, 0x7b, 0x74, 0x73, 0x79, 0x80, + 0x86, 0x87, 0x82, 0x7d, 0x7b, 0x78, 0x7a, 0x7d, 0x7d, 0x7e, 0x82, + 0x82, 0x81, 0x82, 0x82, 0x7f, 0x7f, 0x81, 0x84, 0x87, 0x87, 0x84, + 0x7f, 0x7b, 0x79, 0x7c, 0x7e, 0x80, 0x82, 0x81, 0x80, 0x80, 0x7f, + 0x7f, 0x80, 0x81, 0x81, 0x83, 0x84, 0x82, 0x7e, 0x7b, 0x7a, 0x7a, + 0x77, 0x6d, 0x68, 0x68, 0x64, 0x71, 0x89, 0x8d, 0x8e, 0x8e, 0x81, + 0x7d, 0x80, 0x7b, 0x79, 0x7f, 0x88, 0x8e, 0x91, 0x8f, 0x84, 0x7f, + 0x7f, 0x7c, 0x7e, 0x7e, 0x7e, 0x82, 0x85, 0x85, 0x82, 0x7d, 0x7b, + 0x7c, 0x7e, 0x81, 0x82, 0x80, 0x7e, 0x7e, 0x7e, 0x7b, 0x78, 0x79, + 0x7b, 0x81, 0x85, 0x83, 0x7e, 0x7b, 0x78, 0x76, 0x7b, 0x7d, 0x7d, + 0x80, 0x7f, 0x80, 0x84, 0x83, 0x84, 0x83, 0x83, 0x83, 0x80, 0x80, + 0x7e, 0x7f, 0x82, 0x81, 0x80, 0x81, 0x7f, 0x80, 0x81, 0x80, 0x7f, + 0x7f, 0x7f, 0x80, 0x7f, 0x7e, 0x7c, 0x7b, 0x7c, 0x7d, 0x7f, 0x80, + 0x82, 0x81, 0x7f, 0x82, 0x81, 0x7f, 0x7f, 0x7e, 0x77, 0x71, 0x69, + 0x55, 0x5b, 0x7e, 0x8b, 0x91, 0x95, 0x84, 0x81, 0x84, 0x7d, 0x7a, + 0x7f, 0x89, 0x8d, 0x90, 0x8e, 0x83, 0x80, 0x82, 0x7e, 0x81, 0x85, + 0x84, 0x88, 0x87, 0x82, 0x7d, 0x78, 0x76, 0x77, 0x7a, 0x7f, 0x80, + 0x81, 0x7f, 0x7d, 0x7d, 0x7a, 0x76, 0x79, 0x84, 0x8b, 0x88, 0x80, + 0x78, 0x76, 0x78, 0x7a, 0x7b, 0x7e, 0x86, 0x89, 0x87, 0x81, 0x7c, + 0x7a, 0x7b, 0x7d, 0x81, 0x83, 0x84, 0x81, 0x7d, 0x7c, 0x7b, 0x7d, + 0x7f, 0x81, 0x82, 0x82, 0x80, 0x7d, 0x7b, 0x7d, 0x81, 0x83, 0x83, + 0x81, 0x7e, 0x7d, 0x7e, 0x7d, 0x7d, 0x7e, 0x7e, 0x81, 0x81, 0x7f, + 0x7d, 0x7c, 0x7d, 0x7f, 0x7e, 0x7e, 0x81, 0x82, 0x82, 0x80, 0x74, + 0x68, 0x6a, 0x75, 0x7d, 0x84, 0x88, 0x8a, 0x8a, 0x83, 0x7b, 0x7b, + 0x81, 0x89, 0x8c, 0x8a, 0x88, 0x87, 0x80, 0x7a, 0x79, 0x7c, 0x82, + 0x88, 0x87, 0x83, 0x82, 0x7f, 0x7b, 0x7b, 0x7d, 0x7f, 0x83, 0x82, + 0x7e, 0x7b, 0x7a, 0x79, 0x7a, 0x7a, 0x7d, 0x84, 0x88, 0x85, 0x82, + 0x80, 0x7c, 0x7a, 0x79, 0x79, 0x7d, 0x7f, 0x7e, 0x7c, 0x7d, 0x7e, + 0x80, 0x82, 0x83, 0x83, 0x84, 0x82, 0x7f, 0x7d, 0x7d, 0x7d, 0x7e, + 0x7f, 0x7f, 0x80, 0x7f, 0x7e, 0x7d, 0x7d, 0x7e, 0x80, 0x82, 0x82, + 0x81, 0x7f, 0x7e, 0x7c, 0x7c, 0x7e, 0x80, 0x80, 0x7f, 0x7e, 0x7e, + 0x7f, 0x7f, 0x7e, 0x7f, 0x80, 0x80, 0x7e, 0x7e, 0x7f, 0x7e, 0x7f, + 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x7e, 0x7f, 0x80, 0x7f, 0x7e, 0x7f, + }, + { // 3 + 0x7f, 0x80, 0x81, 0x7e, 0x7a, 0x7c, 0x84, 0x85, 0x7d, 0x7c, 0x81, + 0x82, 0x80, 0x7f, 0x81, 0x81, 0x80, 0x80, 0x7e, 0x80, 0x80, 0x80, + 0x7d, 0x7c, 0x80, 0x81, 0x80, 0x7f, 0x7d, 0x82, 0x7c, 0x7d, 0x80, + 0x7b, 0x7e, 0x81, 0x84, 0x83, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, + 0x81, 0x82, 0x80, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7e, 0x7d, 0x80, + 0x7f, 0x7e, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x81, 0x80, + 0x80, 0x7f, 0x7f, 0x80, 0x79, 0x7a, 0x7f, 0x7e, 0x82, 0x82, 0x80, + 0x83, 0x84, 0x83, 0x85, 0x86, 0x82, 0x7f, 0x80, 0x7f, 0x7b, 0x7c, + 0x7d, 0x7d, 0x7c, 0x7c, 0x7d, 0x80, 0x81, 0x7e, 0x7f, 0x82, 0x82, + 0x80, 0x7f, 0x7f, 0x7f, 0x81, 0x7f, 0x7e, 0x7f, 0x80, 0x80, 0x7f, + 0x7f, 0x80, 0x81, 0x81, 0x80, 0x80, 0x82, 0x82, 0x80, 0x7f, 0x80, + 0x80, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x81, 0x80, + 0x80, 0x80, 0x80, 0x81, 0x82, 0x81, 0x80, 0x82, 0x82, 0x80, 0x7f, + 0x7e, 0x7e, 0x7d, 0x7b, 0x79, 0x73, 0x73, 0x78, 0x74, 0x73, 0x78, + 0x7a, 0x7f, 0x83, 0x87, 0x88, 0x8c, 0x92, 0x8f, 0x8d, 0x8f, 0x8c, + 0x87, 0x82, 0x7e, 0x7a, 0x77, 0x73, 0x72, 0x72, 0x76, 0x7b, 0x7e, + 0x82, 0x87, 0x8b, 0x8d, 0x8f, 0x8e, 0x8c, 0x8b, 0x88, 0x83, 0x80, + 0x7f, 0x7d, 0x7b, 0x7b, 0x7b, 0x7f, 0x82, 0x80, 0x83, 0x87, 0x8a, + 0x83, 0x82, 0x63, 0x45, 0x76, 0x68, 0x3c, 0x56, 0x5f, 0x6c, 0x74, + 0x80, 0x8a, 0x91, 0xc1, 0xb6, 0x95, 0xb7, 0xbc, 0xa0, 0x92, 0x85, + 0x80, 0x72, 0x70, 0x61, 0x49, 0x6f, 0x74, 0x5e, 0x71, 0x84, 0x90, + 0x8f, 0x99, 0x9b, 0x92, 0xa3, 0x8f, 0x75, 0x7f, 0x7a, 0x64, 0x5c, + 0x65, 0x62, 0x6a, 0x78, 0x79, 0x8a, 0x9c, 0x9c, 0x97, 0xa3, 0xa4, + 0x96, 0x92, 0x8b, 0x84, 0x7e, 0x77, 0x6f, 0x73, 0x7c, 0x7b, 0x78, + 0x79, 0x7e, 0x4c, 0x40, 0x84, 0x58, 0x38, 0x66, 0x68, 0x75, 0x7c, + 0x8c, 0x93, 0xa1, 0xcc, 0xa5, 0x95, 0xc2, 0xaa, 0x88, 0x86, 0x7f, + 0x77, 0x64, 0x65, 0x5b, 0x5a, 0x81, 0x6f, 0x6a, 0x90, 0x96, 0x96, + 0x93, 0xa1, 0x9e, 0x8f, 0x94, 0x77, 0x6e, 0x76, 0x63, 0x50, 0x58, + 0x6a, 0x65, 0x70, 0x83, 0x8f, 0x9e, 0xa1, 0x9f, 0xa1, 0xa8, 0x99, + 0x89, 0x8b, 0x83, 0x78, 0x70, 0x71, 0x70, 0x77, 0x7d, 0x7b, 0x87, + 0x89, 0x81, 0x48, 0x51, 0x93, 0x4a, 0x35, 0x69, 0x66, 0x70, 0x6c, + 0x83, 0x96, 0xa4, 0xbd, 0x97, 0xa7, 0xcf, 0x9e, 0x87, 0x91, 0x87, + 0x7a, 0x5f, 0x62, 0x61, 0x62, 0x76, 0x5e, 0x73, 0x98, 0x8a, 0x8d, + 0x97, 0xaa, 0x9f, 0x8b, 0x94, 0x82, 0x7b, 0x6f, 0x59, 0x5e, 0x62, + 0x59, 0x5a, 0x77, 0x83, 0x86, 0x97, 0x9e, 0xa5, 0xa3, 0x9f, 0x96, + 0x95, 0x8f, 0x7c, 0x79, 0x77, 0x71, 0x6e, 0x72, 0x7a, 0x7f, 0x86, + 0x87, 0x8b, 0x54, 0x4b, 0x98, 0x57, 0x30, 0x6a, 0x69, 0x69, 0x62, + 0x80, 0x98, 0x94, 0xb3, 0x9e, 0xa5, 0xcc, 0xa0, 0x8d, 0x99, 0x8e, + 0x7f, 0x60, 0x68, 0x6b, 0x59, 0x6b, 0x61, 0x70, 0x8c, 0x7d, 0x8a, + 0x97, 0xa6, 0x9d, 0x8b, 0x9f, 0x8c, 0x78, 0x76, 0x6a, 0x64, 0x5f, + 0x5e, 0x61, 0x75, 0x7e, 0x7f, 0x91, 0x9b, 0x9c, 0x9b, 0x9f, 0x9a, + 0x92, 0x8f, 0x83, 0x7e, 0x79, 0x74, 0x74, 0x76, 0x7b, 0x7d, 0x80, + 0x84, 0x4e, 0x48, 0x98, 0x58, 0x2f, 0x73, 0x71, 0x69, 0x61, 0x87, + 0x9e, 0x8b, 0xac, 0x9f, 0xa5, 0xc2, 0x98, 0x8e, 0x9d, 0x8e, 0x7b, + 0x64, 0x71, 0x72, 0x56, 0x68, 0x69, 0x73, 0x82, 0x75, 0x8c, 0x95, + 0x9b, 0x95, 0x8d, 0xa0, 0x8a, 0x7a, 0x79, 0x75, 0x69, 0x5d, 0x69, + 0x6b, 0x72, 0x77, 0x82, 0x90, 0x90, 0x95, 0x97, 0x9f, 0x97, 0x8e, + 0x90, 0x88, 0x80, 0x77, 0x79, 0x79, 0x74, 0x7a, 0x7b, 0x81, 0x54, + 0x40, 0x93, 0x64, 0x29, 0x74, 0x78, 0x66, 0x5f, 0x81, 0xa3, 0x83, + 0x9f, 0xa5, 0xa1, 0xbe, 0x98, 0x92, 0xa5, 0x92, 0x80, 0x6b, 0x78, + 0x7a, 0x53, 0x65, 0x6e, 0x6b, 0x75, 0x6c, 0x84, 0x8b, 0x8b, 0x91, + 0x8e, 0x9c, 0x8b, 0x83, 0x89, 0x81, 0x71, 0x6e, 0x7b, 0x6e, 0x6e, + 0x79, 0x7f, 0x82, 0x82, 0x8e, 0x8e, 0x91, 0x8e, 0x8d, 0x90, 0x87, + 0x83, 0x80, 0x81, 0x7a, 0x7d, 0x7c, 0x7e, 0x69, 0x3b, 0x85, 0x77, + 0x27, 0x6b, 0x76, 0x68, 0x5f, 0x71, 0xa0, 0x7f, 0x91, 0xa4, 0x9b, + 0xb8, 0x9e, 0x94, 0xae, 0x9a, 0x8a, 0x7b, 0x7f, 0x87, 0x59, 0x65, + 0x75, 0x63, 0x6a, 0x60, 0x7a, 0x7d, 0x74, 0x87, 0x85, 0x92, 0x88, + 0x8a, 0x93, 0x89, 0x86, 0x80, 0x8a, 0x7d, 0x7a, 0x80, 0x7d, 0x80, + 0x7a, 0x84, 0x84, 0x84, 0x84, 0x83, 0x8a, 0x83, 0x82, 0x84, 0x84, + 0x82, 0x7d, 0x85, 0x66, 0x4e, 0x88, 0x75, 0x37, 0x6c, 0x7d, 0x63, + 0x5a, 0x75, 0x94, 0x71, 0x84, 0x99, 0x8e, 0xa2, 0x99, 0x95, 0x9f, + 0xa0, 0x9a, 0x85, 0x8b, 0x95, 0x7a, 0x73, 0x7e, 0x76, 0x72, 0x6b, + 0x70, 0x76, 0x73, 0x78, 0x75, 0x7c, 0x82, 0x7e, 0x81, 0x84, 0x86, + 0x83, 0x81, 0x81, 0x82, 0x82, 0x7f, 0x81, 0x82, 0x82, 0x82, 0x81, + 0x83, 0x83, 0x81, 0x80, 0x80, 0x7f, 0x7e, 0x7b, 0x7b, 0x7d, 0x7c, + 0x7c, 0x7e, 0x7d, 0x7a, 0x7e, 0x82, 0x7e, 0x7d, 0x80, 0x7f, 0x7e, + 0x7c, 0x7c, 0x7b, 0x7a, 0x7c, 0x7b, 0x7c, 0x7c, 0x7d, 0x80, 0x80, + 0x82, 0x83, 0x83, 0x84, 0x85, 0x84, 0x83, 0x84, 0x86, 0x84, 0x83, + 0x84, 0x86, 0x85, 0x84, 0x84, 0x82, 0x82, 0x81, 0x7d, 0x7c, 0x7c, + 0x7b, 0x79, 0x78, 0x7a, 0x7a, 0x7a, 0x7d, 0x7e, 0x7f, 0x82, 0x84, + 0x83, 0x84, 0x85, 0x83, 0x82, 0x82, 0x80, 0x7e, 0x7e, 0x80, 0x79, + 0x7a, 0x81, 0x79, 0x78, 0x7c, 0x7d, 0x7e, 0x7a, 0x7e, 0x7e, 0x7b, + 0x7f, 0x7e, 0x7c, 0x7d, 0x7e, 0x82, 0x80, 0x80, 0x86, 0x82, 0x84, + 0x86, 0x85, 0x86, 0x83, 0x86, 0x84, 0x7f, 0x82, 0x81, 0x80, 0x7f, + 0x7f, 0x80, 0x7f, 0x81, 0x80, 0x7e, 0x7f, 0x7f, 0x7e, 0x7d, 0x7d, + 0x7c, 0x7b, 0x7c, 0x7d, 0x7c, 0x7d, 0x80, 0x7e, 0x81, 0x82, 0x83, + 0x82, 0x82, 0x84, 0x82, 0x82, 0x83, 0x7d, 0x78, 0x80, 0x7f, 0x76, + 0x77, 0x7a, 0x7d, 0x77, 0x76, 0x7d, 0x7c, 0x7e, 0x7e, 0x7e, 0x81, + 0x81, 0x84, 0x82, 0x81, 0x88, 0x86, 0x81, 0x84, 0x86, 0x85, 0x82, + 0x83, 0x86, 0x80, 0x7f, 0x81, 0x7f, 0x7c, 0x7c, 0x80, 0x7c, 0x7b, + 0x7e, 0x7e, 0x7e, 0x7e, 0x80, 0x80, 0x80, 0x81, 0x7f, 0x7f, 0x80, + 0x80, 0x7d, 0x80, 0x82, 0x7e, 0x7f, 0x81, 0x80, 0x80, 0x82, 0x82, + 0x80, 0x81, 0x82, 0x81, 0x75, 0x7c, 0x86, 0x74, 0x72, 0x7c, 0x7d, + 0x76, 0x6f, 0x7f, 0x7e, 0x75, 0x7f, 0x81, 0x81, 0x82, 0x85, 0x87, + 0x83, 0x8a, 0x8c, 0x80, 0x86, 0x8a, 0x82, 0x7f, 0x7f, 0x87, 0x7f, + 0x79, 0x82, 0x7e, 0x7e, 0x7a, 0x7c, 0x7e, 0x79, 0x7b, 0x7b, 0x7e, + 0x7d, 0x7e, 0x7d, 0x7d, 0x85, 0x7c, 0x81, 0x87, 0x84, 0x83, 0x84, + 0x88, 0x7f, 0x80, 0x82, 0x7f, 0x81, 0x7f, 0x83, 0x81, 0x82, 0x84, + 0x81, 0x6d, 0x7d, 0x8f, 0x5d, 0x6c, 0x88, 0x6e, 0x66, 0x6e, 0x86, + 0x72, 0x6c, 0x8c, 0x80, 0x81, 0x8a, 0x88, 0x90, 0x8f, 0x8b, 0x8d, + 0x8f, 0x91, 0x83, 0x85, 0x93, 0x7e, 0x7c, 0x84, 0x7f, 0x78, 0x71, + 0x7d, 0x75, 0x6d, 0x73, 0x76, 0x75, 0x6e, 0x7b, 0x7f, 0x7b, 0x7f, + 0x87, 0x8e, 0x85, 0x8c, 0x93, 0x8e, 0x8a, 0x8b, 0x8f, 0x82, 0x80, + 0x85, 0x7e, 0x7b, 0x7b, 0x7f, 0x7b, 0x7d, 0x6e, 0x67, 0x8d, 0x64, + 0x55, 0x8a, 0x69, 0x5e, 0x72, 0x76, 0x79, 0x6d, 0x85, 0x87, 0x86, + 0x92, 0x88, 0x9d, 0x9c, 0x87, 0x9c, 0x9c, 0x8b, 0x8b, 0x8c, 0x8f, + 0x7e, 0x7b, 0x85, 0x77, 0x75, 0x6f, 0x76, 0x77, 0x66, 0x71, 0x74, + 0x71, 0x6d, 0x77, 0x7e, 0x74, 0x80, 0x87, 0x89, 0x88, 0x8e, 0x98, + 0x8f, 0x92, 0x95, 0x93, 0x8a, 0x86, 0x8a, 0x80, 0x7b, 0x7b, 0x7c, + 0x76, 0x78, 0x6c, 0x61, 0x89, 0x5f, 0x53, 0x8d, 0x5b, 0x63, 0x77, + 0x67, 0x7c, 0x6d, 0x7d, 0x89, 0x83, 0x8d, 0x8c, 0x9f, 0x96, 0x8f, + 0xa7, 0x99, 0x92, 0x99, 0x8e, 0x92, 0x84, 0x7c, 0x88, 0x76, 0x71, + 0x70, 0x73, 0x6f, 0x62, 0x75, 0x6e, 0x69, 0x75, 0x75, 0x79, 0x78, + 0x81, 0x85, 0x85, 0x89, 0x8e, 0x94, 0x8c, 0x93, 0x95, 0x8e, 0x90, + 0x8d, 0x8c, 0x83, 0x83, 0x81, 0x7a, 0x7c, 0x77, 0x77, 0x62, 0x68, + 0x7f, 0x50, 0x67, 0x79, 0x56, 0x76, 0x67, 0x70, 0x83, 0x6a, 0x89, + 0x89, 0x84, 0x90, 0x8f, 0x9b, 0x90, 0x94, 0xa0, 0x94, 0x95, 0x93, + 0x92, 0x92, 0x83, 0x88, 0x86, 0x78, 0x78, 0x73, 0x75, 0x6b, 0x68, + 0x6e, 0x6c, 0x6b, 0x6a, 0x78, 0x74, 0x76, 0x84, 0x82, 0x88, 0x8a, + 0x92, 0x8f, 0x8d, 0x96, 0x91, 0x8e, 0x8c, 0x8f, 0x89, 0x83, 0x86, + 0x82, 0x7e, 0x7d, 0x7e, 0x7a, 0x71, 0x64, 0x7a, 0x6b, 0x53, 0x7a, + 0x61, 0x63, 0x71, 0x60, 0x83, 0x6c, 0x75, 0x90, 0x7d, 0x8d, 0x8f, + 0x95, 0x9a, 0x8f, 0x9d, 0x9c, 0x92, 0x95, 0x93, 0x93, 0x8b, 0x83, + 0x8b, 0x7f, 0x78, 0x78, 0x76, 0x74, 0x68, 0x6f, 0x6f, 0x68, 0x6b, + 0x6e, 0x73, 0x70, 0x78, 0x82, 0x81, 0x84, 0x8d, 0x91, 0x8e, 0x91, + 0x95, 0x91, 0x8f, 0x8f, 0x8e, 0x88, 0x86, 0x86, 0x80, 0x7e, 0x80, + 0x7d, 0x7b, 0x7b, 0x73, 0x67, 0x7e, 0x6a, 0x59, 0x7f, 0x5e, 0x69, + 0x70, 0x60, 0x85, 0x66, 0x79, 0x8f, 0x76, 0x92, 0x8a, 0x94, 0x9a, + 0x8b, 0x9f, 0x99, 0x91, 0x98, 0x8f, 0x91, 0x8b, 0x84, 0x8a, 0x7e, + 0x7b, 0x7c, 0x76, 0x75, 0x6e, 0x73, 0x71, 0x6b, 0x71, 0x70, 0x74, + 0x71, 0x76, 0x7e, 0x79, 0x80, 0x86, 0x88, 0x88, 0x8d, 0x91, 0x8c, + 0x8e, 0x91, 0x8e, 0x8a, 0x8b, 0x8b, 0x84, 0x82, 0x83, 0x7f, 0x7b, + 0x7d, 0x7e, 0x7a, 0x78, 0x74, 0x6f, 0x7b, 0x69, 0x67, 0x7a, 0x60, + 0x70, 0x6e, 0x69, 0x7f, 0x68, 0x82, 0x84, 0x79, 0x91, 0x86, 0x94, + 0x92, 0x8e, 0x9e, 0x92, 0x93, 0x96, 0x8f, 0x92, 0x8a, 0x86, 0x8a, + 0x7c, 0x7d, 0x7c, 0x75, 0x75, 0x70, 0x74, 0x70, 0x6f, 0x75, 0x74, + 0x75, 0x77, 0x79, 0x7b, 0x7e, 0x7d, 0x82, 0x85, 0x82, 0x89, 0x87, + 0x8a, 0x8a, 0x89, 0x8b, 0x87, 0x8a, 0x87, 0x86, 0x85, 0x84, 0x83, + 0x7f, 0x82, 0x80, 0x7d, 0x81, 0x7e, 0x7d, 0x7a, 0x70, 0x7c, 0x73, + 0x65, 0x7b, 0x67, 0x6d, 0x71, 0x66, 0x7f, 0x69, 0x7a, 0x85, 0x77, + 0x8c, 0x83, 0x8e, 0x92, 0x89, 0x98, 0x93, 0x90, 0x94, 0x8e, 0x91, + 0x8b, 0x85, 0x8d, 0x81, 0x7e, 0x80, 0x7a, 0x7c, 0x73, 0x77, 0x78, + 0x70, 0x75, 0x75, 0x76, 0x76, 0x77, 0x7c, 0x7b, 0x7b, 0x7d, 0x81, + 0x7e, 0x80, 0x85, 0x80, 0x82, 0x84, 0x84, 0x84, 0x84, 0x88, 0x86, + 0x84, 0x88, 0x88, 0x85, 0x86, 0x88, 0x85, 0x83, 0x84, 0x84, 0x82, + 0x83, 0x80, 0x7f, 0x7b, 0x71, 0x7f, 0x6b, 0x69, 0x78, 0x5f, 0x71, + 0x66, 0x68, 0x78, 0x61, 0x7d, 0x78, 0x78, 0x89, 0x81, 0x93, 0x8d, + 0x8e, 0x9d, 0x95, 0x98, 0x99, 0x95, 0x99, 0x8f, 0x8e, 0x90, 0x82, + 0x83, 0x7f, 0x7a, 0x77, 0x70, 0x75, 0x70, 0x6b, 0x70, 0x71, 0x6f, + 0x70, 0x75, 0x78, 0x77, 0x7b, 0x80, 0x80, 0x7f, 0x83, 0x87, 0x82, + 0x86, 0x87, 0x86, 0x87, 0x85, 0x89, 0x85, 0x85, 0x89, 0x84, 0x87, + 0x86, 0x87, 0x84, 0x83, 0x87, 0x82, 0x81, 0x82, 0x82, 0x7e, 0x7e, + 0x7f, 0x79, 0x7d, 0x6b, 0x75, 0x79, 0x5a, 0x78, 0x65, 0x66, 0x75, + 0x5c, 0x83, 0x6b, 0x75, 0x8d, 0x77, 0x92, 0x88, 0x92, 0x9b, 0x8c, + 0x9e, 0x9a, 0x92, 0x98, 0x91, 0x92, 0x8d, 0x84, 0x8b, 0x7f, 0x7b, + 0x7b, 0x75, 0x77, 0x6d, 0x70, 0x72, 0x6c, 0x70, 0x71, 0x74, 0x74, + 0x77, 0x7f, 0x7f, 0x81, 0x87, 0x88, 0x89, 0x89, 0x8a, 0x8a, 0x83, + 0x87, 0x84, 0x7e, 0x81, 0x7d, 0x7e, 0x7a, 0x7b, 0x7e, 0x79, 0x7d, + 0x7e, 0x7f, 0x81, 0x82, 0x85, 0x85, 0x86, 0x88, 0x87, 0x86, 0x88, + 0x87, 0x85, 0x85, 0x86, 0x80, 0x82, 0x7c, 0x6b, 0x84, 0x68, 0x64, + 0x7b, 0x58, 0x75, 0x5f, 0x68, 0x7d, 0x5c, 0x85, 0x78, 0x80, 0x8d, + 0x82, 0x9c, 0x8f, 0x94, 0x9f, 0x95, 0x99, 0x98, 0x94, 0x96, 0x8c, + 0x8d, 0x8a, 0x80, 0x81, 0x7a, 0x79, 0x72, 0x70, 0x72, 0x6c, 0x6d, + 0x6e, 0x70, 0x70, 0x73, 0x78, 0x7a, 0x7d, 0x81, 0x84, 0x86, 0x87, + 0x89, 0x8b, 0x88, 0x8a, 0x86, 0x82, 0x84, 0x7d, 0x7e, 0x7c, 0x7b, + 0x7c, 0x7a, 0x7e, 0x7d, 0x7f, 0x81, 0x81, 0x84, 0x84, 0x86, 0x85, + 0x87, 0x86, 0x85, 0x85, 0x83, 0x84, 0x81, 0x82, 0x81, 0x81, 0x7f, + 0x7f, 0x7f, 0x7e, 0x7b, 0x69, 0x81, 0x71, 0x61, 0x7d, 0x61, 0x75, + 0x67, 0x6d, 0x81, 0x64, 0x86, 0x7d, 0x83, 0x8c, 0x87, 0x9b, 0x8d, + 0x95, 0x9b, 0x94, 0x95, 0x93, 0x94, 0x8e, 0x88, 0x89, 0x83, 0x7e, + 0x7a, 0x7a, 0x76, 0x72, 0x73, 0x72, 0x72, 0x72, 0x75, 0x77, 0x77, + 0x7b, 0x7f, 0x7e, 0x81, 0x85, 0x84, 0x85, 0x84, 0x86, 0x85, 0x80, + 0x83, 0x82, 0x7d, 0x7d, 0x7f, 0x7b, 0x7b, 0x7c, 0x7c, 0x7c, 0x7d, + 0x80, 0x7f, 0x80, 0x84, 0x84, 0x84, 0x86, 0x88, 0x86, 0x86, 0x87, + 0x86, 0x83, 0x83, 0x83, 0x7f, 0x7f, 0x7e, 0x7c, 0x7a, 0x7a, 0x7c, + 0x7a, 0x7b, 0x7d, 0x7d, 0x7c, 0x80, 0x7c, 0x77, 0x80, 0x76, 0x76, + 0x77, 0x75, 0x79, 0x72, 0x7b, 0x7a, 0x7a, 0x82, 0x82, 0x87, 0x87, + 0x8c, 0x8f, 0x8c, 0x8f, 0x90, 0x8d, 0x8b, 0x8a, 0x88, 0x83, 0x81, + 0x81, 0x7d, 0x7c, 0x7c, 0x7b, 0x7b, 0x7b, 0x7e, 0x7c, 0x7c, 0x7e, + 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x7e, 0x7f, 0x81, 0x7f, 0x80, 0x80, + 0x80, 0x7f, 0x80, 0x7f, 0x7d, 0x7f, 0x7d, 0x7d, 0x7d, 0x7d, 0x7f, + 0x7c, 0x7f, 0x81, 0x7f, 0x81, 0x81, 0x83, 0x81, 0x81, 0x84, 0x82, + 0x81, 0x82, 0x82, 0x80, 0x7f, 0x81, 0x80, 0x7e, 0x81, 0x81, 0x7f, + 0x81, 0x81, 0x80, 0x7f, 0x80, 0x7f, 0x7d, 0x7e, 0x7e, 0x7e, 0x7c, + 0x7d, 0x7e, 0x7d, 0x7e, 0x7d, 0x7e, 0x80, 0x7e, 0x7f, 0x7e, 0x7f, + 0x7e, 0x7d, 0x7f, 0x7d, 0x7e, 0x7f, 0x7f, 0x81, 0x81, 0x82, 0x84, + 0x84, 0x85, 0x85, 0x85, 0x85, 0x83, 0x84, 0x82, 0x80, 0x82, 0x80, + 0x80, 0x80, 0x7f, 0x80, 0x80, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, + 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x81, 0x80, 0x81, 0x81, 0x81, 0x81, + 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7e, 0x7e, 0x7d, 0x7d, 0x7d, 0x7d, + 0x7d, 0x7d, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x80, 0x7e, 0x7f, 0x81, + 0x7f, 0x80, 0x80, 0x80, 0x82, 0x80, 0x81, 0x83, 0x80, 0x81, 0x81, + 0x7f, 0x80, 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x7d, 0x7e, 0x7f, 0x7e, + 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x81, 0x7f, 0x81, 0x81, 0x7f, 0x82, + 0x80, 0x81, 0x81, 0x80, 0x82, 0x80, 0x80, 0x81, 0x7f, 0x80, 0x80, + 0x7e, 0x7e, 0x7e, 0x7e, 0x7d, 0x7e, 0x7f, 0x7f, 0x80, 0x80, 0x81, + 0x80, 0x81, 0x81, 0x7f, 0x81, 0x7f, 0x7f, 0x80, 0x7e, 0x7e, 0x7f, + 0x7f, 0x7e, 0x7e, 0x7f, 0x7f, 0x7e, 0x7f, 0x81, 0x7f, 0x80, 0x81, + 0x80, 0x82, 0x80, 0x81, 0x81, 0x81, 0x81, 0x80, 0x81, 0x80, 0x81, + 0x7f, 0x7f, 0x80, 0x7e, 0x7f, 0x7d, 0x7d, 0x7f, 0x7c, 0x7e, 0x7f, + 0x7e, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x82, 0x80, 0x80, 0x82, 0x80, + 0x80, 0x80, 0x81, 0x80, 0x80, 0x80, 0x81, 0x80, 0x7e, 0x81, 0x7f, + 0x7e, 0x7f, 0x7d, 0x7f, 0x7e, 0x7d, 0x80, 0x7c, 0x7e, 0x80, 0x7e, + 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x81, 0x7f, + 0x81, 0x82, 0x81, 0x81, 0x82, 0x81, 0x82, 0x82, 0x81, 0x81, 0x80, + 0x7f, 0x7e, 0x7d, 0x7d, 0x7d, 0x7c, 0x7c, 0x7d, 0x7e, 0x7e, 0x7f, + 0x81, 0x80, 0x81, 0x83, 0x82, 0x80, 0x81, 0x81, 0x80, 0x7f, 0x7f, + 0x7f, 0x7e, 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x81, 0x80, 0x7f, 0x80, + 0x7f, 0x7e, 0x7f, 0x7e, 0x7e, 0x7f, 0x7f, 0x80, 0x80, 0x81, 0x81, + 0x81, 0x82, 0x82, 0x81, 0x81, 0x80, 0x80, 0x7f, 0x7e, 0x7e, 0x7d, + 0x7c, 0x7d, 0x7c, 0x7d, 0x7d, 0x7e, 0x7f, 0x7f, 0x80, 0x80, 0x80, + 0x82, 0x81, 0x81, 0x81, 0x82, 0x81, 0x81, 0x82, 0x80, 0x82, 0x81, + 0x81, 0x82, 0x80, 0x82, 0x81, 0x7f, 0x80, 0x7e, 0x7d, 0x7d, 0x7b, + 0x7b, 0x7c, 0x7b, 0x7c, 0x7d, 0x7d, 0x7f, 0x7f, 0x80, 0x80, 0x80, + 0x81, 0x80, 0x81, 0x81, 0x7f, 0x81, 0x80, 0x80, 0x82, 0x80, 0x82, + 0x81, 0x7f, 0x81, 0x7f, 0x80, 0x7f, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x81, 0x7f, 0x80, 0x81, 0x7f, 0x81, 0x80, 0x7f, 0x80, 0x80, + 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x81, 0x80, 0x80, + 0x80, 0x7f, 0x80, 0x7f, 0x7e, 0x7f, 0x7f, 0x7e, 0x7f, 0x7e, 0x7f, + 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x7f, + 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x7f, + 0x7f, 0x7f, + }, + { // 4 + 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, + 0x7e, 0x7f, 0x80, 0x7d, 0x7f, 0x80, 0x7e, 0x7f, 0x7e, 0x81, 0x7f, + 0x81, 0x80, 0x7f, 0x7f, 0x7f, 0x80, 0x7e, 0x80, 0x7e, 0x7f, 0x7f, + 0x7e, 0x7f, 0x80, 0x7e, 0x7f, 0x7f, 0x7f, 0x7e, 0x80, 0x81, 0x7d, + 0x80, 0x7f, 0x79, 0x81, 0x7c, 0x7c, 0x84, 0x80, 0x81, 0x81, 0x80, + 0x85, 0x7a, 0x82, 0x80, 0x7d, 0x81, 0x7a, 0x80, 0x7d, 0x7e, 0x7e, + 0x80, 0x7e, 0x7f, 0x7f, 0x7c, 0x86, 0x7d, 0x7e, 0x85, 0x7b, 0x81, + 0x83, 0x76, 0x88, 0x78, 0x82, 0x83, 0x76, 0x88, 0x7a, 0x7f, 0x83, + 0x7a, 0x84, 0x7a, 0x80, 0x85, 0x73, 0x8b, 0x79, 0x7e, 0x85, 0x75, + 0x8b, 0x75, 0x83, 0x84, 0x75, 0x8a, 0x78, 0x80, 0x86, 0x75, 0x83, + 0x7d, 0x7d, 0x84, 0x7b, 0x85, 0x7f, 0x7d, 0x7e, 0x7f, 0x84, 0x77, + 0x88, 0x7d, 0x79, 0x8b, 0x71, 0x87, 0x84, 0x6e, 0x8f, 0x77, 0x7a, + 0x89, 0x78, 0x84, 0x7d, 0x7e, 0x82, 0x80, 0x79, 0x7f, 0x89, 0x75, + 0x85, 0x81, 0x74, 0x8f, 0x71, 0x7e, 0x8e, 0x6f, 0x84, 0x86, 0x76, + 0x82, 0x80, 0x80, 0x7d, 0x77, 0x8c, 0x7c, 0x7c, 0x80, 0x80, 0x7d, + 0x7d, 0x84, 0x77, 0x89, 0x7e, 0x76, 0x8d, 0x76, 0x7a, 0x8d, 0x70, + 0x85, 0x8a, 0x6d, 0x8b, 0x81, 0x6f, 0x8c, 0x7f, 0x73, 0x8e, 0x7e, + 0x74, 0x8c, 0x79, 0x7a, 0x8c, 0x71, 0x85, 0x85, 0x74, 0x84, 0x83, + 0x79, 0x7d, 0x8a, 0x74, 0x84, 0x7e, 0x7d, 0x86, 0x77, 0x8a, 0x77, + 0x7e, 0x85, 0x78, 0x81, 0x81, 0x7e, 0x84, 0x7a, 0x7d, 0x83, 0x7b, + 0x83, 0x77, 0x8d, 0x76, 0x80, 0x8a, 0x6d, 0x91, 0x78, 0x76, 0x8b, + 0x7c, 0x78, 0x87, 0x7b, 0x80, 0x7f, 0x7c, 0x83, 0x75, 0x8a, 0x7c, + 0x7b, 0x87, 0x79, 0x7f, 0x81, 0x7d, 0x7f, 0x83, 0x7a, 0x84, 0x7e, + 0x7d, 0x84, 0x77, 0x84, 0x7d, 0x81, 0x81, 0x7b, 0x8b, 0x72, 0x78, + 0x94, 0x6f, 0x7b, 0x98, 0x6d, 0x7b, 0x94, 0x65, 0x87, 0x8e, 0x6c, + 0x8c, 0x7b, 0x80, 0x82, 0x74, 0x8d, 0x79, 0x78, 0x8c, 0x79, 0x7e, + 0x7e, 0x86, 0x7d, 0x77, 0x8d, 0x76, 0x77, 0x91, 0x77, 0x75, 0x93, + 0x76, 0x78, 0x8c, 0x74, 0x83, 0x7b, 0x7e, 0x87, 0x77, 0x86, 0x7c, + 0x78, 0x8c, 0x7c, 0x76, 0x8d, 0x74, 0x7f, 0x8f, 0x6d, 0x8a, 0x7f, + 0x74, 0x8f, 0x71, 0x84, 0x86, 0x78, 0x87, 0x75, 0x88, 0x7d, 0x75, + 0x86, 0x7e, 0x7e, 0x82, 0x7a, 0x85, 0x83, 0x72, 0x89, 0x80, 0x73, + 0x8b, 0x7d, 0x7a, 0x8c, 0x76, 0x81, 0x7f, 0x7e, 0x83, 0x7a, 0x80, + 0x82, 0x7e, 0x7d, 0x83, 0x7e, 0x7c, 0x84, 0x7c, 0x7e, 0x84, 0x7a, + 0x80, 0x83, 0x7e, 0x80, 0x7f, 0x7a, 0x84, 0x7f, 0x77, 0x88, 0x7b, + 0x7d, 0x82, 0x7d, 0x7f, 0x7f, 0x80, 0x79, 0x87, 0x81, 0x71, 0x8d, + 0x80, 0x75, 0x89, 0x7e, 0x79, 0x8a, 0x7a, 0x7b, 0x8a, 0x73, 0x7f, + 0x87, 0x76, 0x81, 0x86, 0x7b, 0x7d, 0x89, 0x78, 0x7c, 0x8a, 0x79, + 0x7e, 0x88, 0x79, 0x7b, 0x88, 0x73, 0x82, 0x8a, 0x72, 0x88, 0x82, + 0x74, 0x83, 0x80, 0x7e, 0x84, 0x7e, 0x7e, 0x82, 0x7c, 0x82, 0x7b, + 0x7f, 0x88, 0x74, 0x87, 0x86, 0x6f, 0x8e, 0x7f, 0x74, 0x8a, 0x7a, + 0x7b, 0x87, 0x7c, 0x7b, 0x85, 0x7f, 0x7e, 0x82, 0x7f, 0x81, 0x7e, + 0x80, 0x83, 0x7e, 0x7e, 0x7e, 0x7f, 0x7a, 0x82, 0x7f, 0x7a, 0x88, + 0x7d, 0x81, 0x83, 0x7e, 0x83, 0x7a, 0x82, 0x7b, 0x7e, 0x80, 0x7b, + 0x83, 0x81, 0x80, 0x7f, 0x86, 0x78, 0x84, 0x84, 0x75, 0x88, 0x7f, + 0x7b, 0x84, 0x7c, 0x7f, 0x81, 0x7c, 0x7c, 0x85, 0x79, 0x80, 0x84, + 0x7a, 0x83, 0x83, 0x7d, 0x81, 0x7f, 0x83, 0x76, 0x87, 0x81, 0x73, + 0x89, 0x7f, 0x78, 0x86, 0x81, 0x78, 0x88, 0x81, 0x75, 0x8d, 0x7d, + 0x7a, 0x86, 0x7a, 0x81, 0x7d, 0x7d, 0x7e, 0x7f, 0x7d, 0x7c, 0x7f, + 0x7b, 0x81, 0x7a, 0x7c, 0x81, 0x7d, 0x7b, 0x82, 0x81, 0x7c, 0x86, + 0x85, 0x7e, 0x8a, 0x85, 0x82, 0x89, 0x85, 0x83, 0x8b, 0x83, 0x83, + 0x86, 0x80, 0x81, 0x80, 0x7b, 0x81, 0x82, 0x78, 0x85, 0x7e, 0x79, + 0x81, 0x7a, 0x7c, 0x81, 0x80, 0x7d, 0x83, 0x7e, 0x80, 0x84, 0x7b, + 0x88, 0x81, 0x84, 0x61, 0x68, 0x91, 0x52, 0x64, 0x75, 0x61, 0x77, + 0x66, 0x74, 0x81, 0x89, 0x87, 0x87, 0xa5, 0x99, 0x9b, 0x9e, 0x9e, + 0xa0, 0x97, 0x8f, 0x8a, 0x8d, 0x80, 0x72, 0x77, 0x76, 0x6a, 0x68, + 0x6c, 0x6d, 0x70, 0x70, 0x78, 0x80, 0x81, 0x81, 0x8b, 0x8d, 0x8a, + 0x8c, 0x8e, 0x8c, 0x88, 0x85, 0x84, 0x85, 0x7d, 0x7a, 0x7e, 0x7b, + 0x79, 0x79, 0x7c, 0x7e, 0x7c, 0x81, 0x7f, 0x84, 0x88, 0x84, 0x83, + 0x53, 0x6b, 0x95, 0x3e, 0x53, 0x79, 0x57, 0x69, 0x61, 0x6f, 0x7f, + 0x8c, 0x8a, 0x83, 0xb1, 0xaa, 0x96, 0xa5, 0xac, 0xa3, 0x9c, 0x93, + 0x8a, 0x91, 0x82, 0x72, 0x72, 0x78, 0x6b, 0x63, 0x69, 0x6c, 0x6e, + 0x65, 0x72, 0x79, 0x79, 0x7d, 0x84, 0x8c, 0x89, 0x8d, 0x8e, 0x90, + 0x90, 0x8a, 0x8b, 0x8b, 0x85, 0x7f, 0x80, 0x83, 0x77, 0x7b, 0x7c, + 0x7a, 0x79, 0x7d, 0x7d, 0x7e, 0x85, 0x7d, 0x86, 0x84, 0x86, 0x62, + 0x4d, 0x98, 0x58, 0x37, 0x7b, 0x5b, 0x60, 0x64, 0x6c, 0x77, 0x86, + 0x98, 0x7d, 0xa0, 0xbb, 0x9c, 0x9d, 0xb1, 0xa9, 0x9c, 0x9b, 0x8a, + 0x8d, 0x89, 0x7a, 0x6b, 0x71, 0x78, 0x5f, 0x63, 0x6c, 0x70, 0x67, + 0x66, 0x7a, 0x79, 0x7b, 0x7b, 0x89, 0x8f, 0x89, 0x8d, 0x8f, 0x98, + 0x8c, 0x89, 0x8e, 0x8a, 0x83, 0x7c, 0x82, 0x7f, 0x79, 0x77, 0x7a, + 0x7c, 0x78, 0x7b, 0x7e, 0x81, 0x82, 0x7d, 0x85, 0x85, 0x87, 0x7e, + 0x41, 0x70, 0x95, 0x33, 0x50, 0x73, 0x5e, 0x61, 0x5e, 0x78, 0x77, + 0x98, 0x90, 0x7d, 0xb4, 0xb8, 0x98, 0x9e, 0xb5, 0xa7, 0x9b, 0x92, + 0x8c, 0x89, 0x86, 0x75, 0x63, 0x77, 0x74, 0x5b, 0x61, 0x6f, 0x75, + 0x68, 0x69, 0x75, 0x84, 0x7e, 0x78, 0x88, 0x94, 0x8d, 0x86, 0x90, + 0x95, 0x8d, 0x87, 0x84, 0x88, 0x85, 0x7b, 0x78, 0x80, 0x7d, 0x75, + 0x78, 0x79, 0x7b, 0x7b, 0x79, 0x7e, 0x80, 0x81, 0x7d, 0x85, 0x87, + 0x8b, 0x7d, 0x42, 0x79, 0x8c, 0x3c, 0x57, 0x6b, 0x68, 0x5e, 0x63, + 0x76, 0x72, 0x9a, 0x8c, 0x81, 0xa8, 0xb3, 0x9e, 0x96, 0xae, 0xa8, + 0x99, 0x94, 0x8c, 0x87, 0x89, 0x7b, 0x6a, 0x72, 0x76, 0x6b, 0x63, + 0x6f, 0x75, 0x6e, 0x71, 0x72, 0x7c, 0x81, 0x7e, 0x7d, 0x88, 0x91, + 0x86, 0x84, 0x8a, 0x8c, 0x87, 0x81, 0x82, 0x84, 0x81, 0x79, 0x78, + 0x7a, 0x7e, 0x78, 0x76, 0x7c, 0x7e, 0x7b, 0x7b, 0x7c, 0x83, 0x81, + 0x7d, 0x80, 0x84, 0x87, 0x83, 0x8c, 0x69, 0x5c, 0x8f, 0x6f, 0x54, + 0x67, 0x6e, 0x6b, 0x60, 0x73, 0x6a, 0x79, 0x8e, 0x80, 0x85, 0x98, + 0xa6, 0x96, 0x97, 0xa6, 0x9f, 0x9b, 0x98, 0x8e, 0x87, 0x8c, 0x85, + 0x72, 0x75, 0x7c, 0x70, 0x6a, 0x72, 0x73, 0x70, 0x72, 0x74, 0x74, + 0x7e, 0x7e, 0x79, 0x7d, 0x87, 0x84, 0x7f, 0x81, 0x85, 0x83, 0x83, + 0x81, 0x7f, 0x84, 0x81, 0x7d, 0x7c, 0x81, 0x7f, 0x7a, 0x7c, 0x7d, + 0x7d, 0x7d, 0x7c, 0x7d, 0x7f, 0x7e, 0x7e, 0x7d, 0x81, 0x80, 0x7f, + 0x80, 0x82, 0x82, 0x80, 0x76, 0x77, 0x7c, 0x77, 0x75, 0x72, 0x75, + 0x75, 0x75, 0x79, 0x77, 0x7c, 0x82, 0x84, 0x86, 0x89, 0x8d, 0x8c, + 0x8d, 0x8b, 0x8b, 0x89, 0x8a, 0x86, 0x84, 0x83, 0x82, 0x82, 0x7e, + 0x7f, 0x7c, 0x7d, 0x7e, 0x7c, 0x7a, 0x7c, 0x7c, 0x7b, 0x7b, 0x7c, + 0x7c, 0x7d, 0x7e, 0x7d, 0x7e, 0x7f, 0x81, 0x80, 0x80, 0x80, 0x82, + 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x7d, 0x7e, 0x7e, 0x7e, 0x7c, + 0x7e, 0x7e, 0x7e, 0x7d, 0x7d, 0x7c, 0x7e, 0x7d, 0x7d, 0x7d, 0x7e, + 0x7f, 0x7e, 0x7f, 0x7f, 0x81, 0x80, 0x81, 0x81, 0x81, 0x82, 0x81, + 0x80, 0x7f, 0x80, 0x7f, 0x7e, 0x7f, 0x7d, 0x7f, 0x7e, 0x7d, 0x7e, + 0x7d, 0x7f, 0x7e, 0x7f, 0x80, 0x81, 0x80, 0x81, 0x81, 0x83, 0x82, + 0x83, 0x82, 0x84, 0x82, 0x82, 0x82, 0x81, 0x82, 0x81, 0x81, 0x7f, + 0x81, 0x7f, 0x7e, 0x80, 0x7e, 0x7e, 0x7c, 0x7d, 0x7d, 0x7c, 0x7d, + 0x7b, 0x7c, 0x7d, 0x7d, 0x7c, 0x7e, 0x7d, 0x80, 0x7d, 0x80, 0x7f, + 0x80, 0x80, 0x80, 0x7f, 0x81, 0x7f, 0x80, 0x7f, 0x80, 0x7e, 0x7f, + 0x7e, 0x7d, 0x7e, 0x7d, 0x7e, 0x7d, 0x7e, 0x7f, 0x7f, 0x7e, 0x7f, + 0x7e, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x81, 0x81, 0x7f, 0x81, 0x81, + 0x82, 0x81, 0x80, 0x81, 0x80, 0x81, 0x7f, 0x80, 0x7f, 0x80, 0x7f, + 0x7f, 0x7f, 0x7f, 0x80, 0x7e, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, + 0x7e, 0x7f, 0x7e, 0x7d, 0x7f, 0x7d, 0x7f, 0x7e, 0x7f, 0x7f, 0x80, + 0x7f, 0x81, 0x80, 0x80, 0x81, 0x7f, 0x80, 0x7f, 0x7e, 0x7f, 0x7d, + 0x7e, 0x7d, 0x7d, 0x7d, 0x7f, 0x7d, 0x7d, 0x7f, 0x7e, 0x80, 0x80, + 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x80, + 0x80, 0x7f, 0x81, 0x7f, 0x81, 0x80, 0x81, 0x80, 0x7f, 0x80, 0x7f, + 0x80, 0x7f, 0x7d, 0x7f, 0x7d, 0x7e, 0x7d, 0x7f, 0x7e, 0x7f, 0x7f, + 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x81, 0x7f, + 0x80, 0x7f, 0x81, 0x81, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x7d, 0x7d, + 0x7d, 0x7c, 0x7d, 0x7c, 0x7d, 0x7e, 0x7d, 0x7f, 0x7e, 0x80, 0x80, + 0x81, 0x82, 0x81, 0x81, 0x80, 0x81, 0x80, 0x80, 0x7f, 0x80, 0x80, + 0x7d, 0x7e, 0x7f, 0x7f, 0x7d, 0x7f, 0x7e, 0x7f, 0x7e, 0x7f, 0x7e, + 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x80, 0x7e, 0x80, 0x7e, 0x7f, 0x7f, + 0x7e, 0x7f, 0x7f, 0x7f, 0x80, 0x7e, 0x80, 0x7f, 0x80, 0x7f, 0x80, + 0x7f, 0x80, 0x7e, 0x80, 0x7e, 0x80, 0x7e, 0x7f, 0x7e, 0x7e, 0x7e, + 0x7f, 0x7d, 0x7e, 0x7e, 0x7f, 0x7e, 0x7f, 0x7f, 0x7e, 0x7f, 0x7f, + 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x81, + 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x7e, 0x7f, + 0x7e, 0x7f, 0x7e, 0x7f, 0x7e, 0x7f, 0x7e, 0x7f, 0x7e, 0x7f, 0x80, + 0x7e, 0x80, 0x7e, 0x7e, 0x81, 0x7e, 0x7f, 0x80, 0x80, 0x80, 0x80, + 0x7f, 0x80, 0x81, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x80, 0x7e, + 0x7f, 0x7e, 0x7f, 0x7d, 0x7f, 0x7e, 0x7d, 0x7c, 0x77, 0x82, 0x82, + 0x7e, 0x80, 0x7e, 0x7e, 0x7f, 0x7e, 0x7f, 0x7f, 0x83, 0x7f, 0x7c, + 0x86, 0x75, 0x7c, 0x85, 0x81, 0x85, 0x84, 0x82, 0x7b, 0x7e, 0x81, + 0x80, 0x7f, 0x7b, 0x7d, 0x7e, 0x7d, 0x7f, 0x7f, 0x7e, 0x7f, 0x7e, + 0x7f, 0x81, 0x80, 0x7f, 0x80, 0x7e, 0x80, 0x7f, 0x81, 0x7e, 0x7e, + 0x7f, 0x7e, 0x7e, 0x80, 0x7c, 0x7d, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, + 0x79, 0x7c, 0x82, 0x82, 0x82, 0x84, 0x81, 0x80, 0x81, 0x78, 0x7f, + 0x7e, 0x7f, 0x7c, 0x79, 0x7e, 0x7d, 0x7f, 0x75, 0x7f, 0x85, 0x82, + 0x85, 0x86, 0x85, 0x83, 0x7f, 0x7c, 0x82, 0x83, 0x81, 0x80, 0x7e, + 0x80, 0x7d, 0x7b, 0x7c, 0x7c, 0x7d, 0x7c, 0x78, 0x7b, 0x7c, 0x7e, + 0x7e, 0x7d, 0x80, 0x81, 0x81, 0x80, 0x83, 0x84, 0x82, 0x81, 0x7f, + 0x80, 0x7f, 0x7f, 0x7f, 0x7c, 0x7f, 0x7d, 0x7f, 0x7d, 0x7e, 0x7f, + 0x7f, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x7d, 0x7e, + 0x7f, 0x7c, 0x7e, 0x7f, 0x80, 0x80, 0x7d, 0x81, 0x7f, 0x7d, 0x81, + 0x7e, 0x80, 0x81, 0x7f, 0x80, 0x81, 0x82, 0x7e, 0x81, 0x83, 0x80, + 0x81, 0x81, 0x80, 0x80, 0x81, 0x80, 0x7f, 0x7f, 0x7f, 0x7d, 0x7c, + 0x81, 0x7c, 0x7d, 0x7f, 0x7a, 0x80, 0x81, 0x7c, 0x7e, 0x83, 0x80, + 0x7d, 0x7f, 0x83, 0x81, 0x81, 0x7f, 0x7f, 0x7f, 0x81, 0x7a, 0x7e, + 0x81, 0x7d, 0x7d, 0x7c, 0x7e, 0x7f, 0x7d, 0x7d, 0x81, 0x7d, 0x7f, + 0x7d, 0x7b, 0x7c, 0x7a, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7f, 0x7e, + 0x82, 0x84, 0x85, 0x87, 0x89, 0x8a, 0x8b, 0x8d, 0x88, 0x8a, 0x8a, + 0x85, 0x84, 0x83, 0x83, 0x7f, 0x80, 0x7e, 0x81, 0x7e, 0x7b, 0x7d, + 0x7e, 0x7d, 0x7d, 0x7d, 0x7f, 0x7d, 0x7f, 0x80, 0x7f, 0x80, 0x6d, + 0x58, 0x70, 0x77, 0x59, 0x5e, 0x65, 0x6f, 0x71, 0x75, 0x7e, 0x7b, + 0x93, 0xa3, 0x94, 0x92, 0xa3, 0xab, 0x9e, 0x94, 0x98, 0x92, 0x8e, + 0x89, 0x79, 0x72, 0x76, 0x6d, 0x64, 0x69, 0x6b, 0x6e, 0x72, 0x7c, + 0x7e, 0x82, 0x8f, 0x8d, 0x90, 0x92, 0x96, 0x93, 0x8e, 0x90, 0x89, + 0x87, 0x82, 0x7d, 0x7a, 0x7a, 0x7d, 0x78, 0x7e, 0x7d, 0x7c, 0x6c, + 0x40, 0x65, 0x7c, 0x45, 0x4b, 0x58, 0x67, 0x6c, 0x64, 0x82, 0x7a, + 0x8f, 0xb6, 0x9d, 0x96, 0xb3, 0xbf, 0xac, 0x96, 0x9d, 0xa2, 0x89, + 0x84, 0x7f, 0x63, 0x72, 0x77, 0x61, 0x58, 0x60, 0x74, 0x60, 0x62, + 0x7d, 0x76, 0x82, 0x89, 0x8f, 0x8e, 0x96, 0xa3, 0x8d, 0x93, 0x9d, + 0x94, 0x8a, 0x8b, 0x91, 0x7f, 0x7e, 0x87, 0x7d, 0x7e, 0x82, 0x81, + 0x7d, 0x6c, 0x44, 0x5c, 0x7d, 0x3e, 0x3f, 0x55, 0x5e, 0x69, 0x52, + 0x7a, 0x7e, 0x89, 0xb5, 0x98, 0x9c, 0xbd, 0xc5, 0xb3, 0x98, 0xab, + 0xb1, 0x8e, 0x80, 0x81, 0x6d, 0x71, 0x6e, 0x54, 0x59, 0x5e, 0x73, + 0x64, 0x57, 0x77, 0x77, 0x7e, 0x81, 0x83, 0x94, 0x91, 0x9c, 0x8d, + 0x8f, 0xa0, 0x94, 0x8c, 0x8a, 0x93, 0x90, 0x80, 0x84, 0x83, 0x86, + 0x85, 0x80, 0x84, 0x7e, 0x81, 0x58, 0x40, 0x78, 0x64, 0x31, 0x48, + 0x57, 0x66, 0x57, 0x5d, 0x81, 0x7d, 0x9c, 0xab, 0x90, 0xad, 0xc8, + 0xbb, 0xa6, 0x9e, 0xb9, 0xa8, 0x7f, 0x84, 0x7e, 0x6f, 0x73, 0x5d, + 0x56, 0x5e, 0x65, 0x6b, 0x53, 0x6a, 0x87, 0x75, 0x78, 0x81, 0x90, + 0x92, 0x87, 0x92, 0x8c, 0x96, 0x95, 0x83, 0x89, 0x90, 0x8f, 0x7f, + 0x81, 0x91, 0x84, 0x80, 0x84, 0x88, 0x89, 0x85, 0x89, 0x80, 0x71, + 0x56, 0x60, 0x73, 0x42, 0x41, 0x58, 0x57, 0x5a, 0x54, 0x6f, 0x7e, + 0x83, 0x9e, 0x99, 0x9f, 0xbd, 0xbb, 0xab, 0xa7, 0xb4, 0xb0, 0x91, + 0x85, 0x8d, 0x7b, 0x71, 0x6a, 0x59, 0x62, 0x61, 0x61, 0x5c, 0x60, + 0x7b, 0x76, 0x6f, 0x81, 0x8a, 0x89, 0x86, 0x8f, 0x8e, 0x8c, 0x93, + 0x89, 0x86, 0x8b, 0x8b, 0x82, 0x7f, 0x8b, 0x87, 0x84, 0x83, 0x87, + 0x8b, 0x87, 0x88, 0x89, 0x88, 0x84, 0x76, 0x5a, 0x57, 0x74, 0x54, + 0x35, 0x53, 0x5c, 0x5b, 0x51, 0x62, 0x80, 0x8e, 0x93, 0xab, 0xaa, + 0x9c, 0xb3, 0xb5, 0xa2, 0x9e, 0x9d, 0x95, 0x8a, 0x7a, 0x79, 0x70, + 0x6d, 0x67, 0x59, 0x69, 0x6b, 0x60, 0x68, 0x72, 0x7e, 0x7d, 0x7f, + 0x8a, 0x8d, 0x93, 0x8c, 0x8c, 0x95, 0x89, 0x83, 0x82, 0x82, 0x78, + 0x74, 0x78, 0x73, 0x76, 0x75, 0x79, 0x80, 0x83, 0x84, 0x89, 0x90, + 0x91, 0x90, 0x95, 0x93, 0x93, 0x91, 0x8d, 0x82, 0x70, 0x61, 0x6b, + 0x64, 0x3c, 0x51, 0x5a, 0x49, 0x54, 0x57, 0x69, 0x77, 0x7e, 0x8a, + 0x93, 0xad, 0xae, 0xa2, 0xb7, 0xba, 0xaa, 0xa7, 0xa0, 0x9a, 0x92, + 0x7f, 0x79, 0x72, 0x6e, 0x66, 0x58, 0x65, 0x67, 0x5f, 0x66, 0x6d, + 0x79, 0x79, 0x7c, 0x85, 0x89, 0x8e, 0x8c, 0x85, 0x93, 0x8d, 0x7f, + 0x83, 0x87, 0x7c, 0x75, 0x7d, 0x7b, 0x79, 0x7d, 0x7e, 0x82, 0x87, + 0x86, 0x8a, 0x91, 0x90, 0x8a, 0x91, 0x90, 0x8a, 0x89, 0x87, 0x87, + 0x7d, 0x73, 0x60, 0x5a, 0x71, 0x4e, 0x3d, 0x60, 0x56, 0x51, 0x5b, + 0x66, 0x79, 0x7c, 0x8a, 0x91, 0xa0, 0xb5, 0xa8, 0xa5, 0xbf, 0xb5, + 0xa5, 0xa3, 0x9e, 0x9a, 0x87, 0x7d, 0x77, 0x6c, 0x6f, 0x5c, 0x58, + 0x68, 0x63, 0x5d, 0x64, 0x6e, 0x76, 0x73, 0x7c, 0x85, 0x89, 0x8e, + 0x8b, 0x90, 0x95, 0x8c, 0x8c, 0x8a, 0x89, 0x82, 0x7f, 0x7f, 0x7d, + 0x7e, 0x79, 0x7d, 0x7e, 0x7f, 0x7c, 0x80, 0x84, 0x7f, 0x81, 0x7f, + 0x7f, 0x80, 0x80, 0x7d, 0x7f, 0x81, 0x7f, 0x7e, 0x7f, 0x7d, 0x77, + 0x73, 0x7d, 0x72, 0x6c, 0x73, 0x70, 0x70, 0x71, 0x74, 0x78, 0x79, + 0x81, 0x82, 0x82, 0x8d, 0x8e, 0x8b, 0x92, 0x92, 0x91, 0x8f, 0x8f, + 0x8f, 0x89, 0x8a, 0x87, 0x7f, 0x82, 0x7f, 0x7b, 0x79, 0x7b, 0x79, + 0x75, 0x77, 0x79, 0x78, 0x77, 0x7b, 0x79, 0x7b, 0x7d, 0x7b, 0x7d, + 0x7e, 0x81, 0x7d, 0x7d, 0x82, 0x7d, 0x7e, 0x80, 0x81, 0x80, 0x80, + 0x81, 0x7f, 0x82, 0x81, 0x81, 0x82, 0x84, 0x81, 0x81, 0x82, 0x82, + 0x80, 0x83, 0x81, 0x81, 0x80, 0x82, 0x81, 0x81, 0x81, 0x80, 0x7f, + 0x80, 0x7d, 0x7d, 0x7d, 0x78, 0x77, 0x7b, 0x76, 0x6f, 0x76, 0x72, + 0x72, 0x74, 0x75, 0x76, 0x79, 0x7e, 0x7f, 0x7f, 0x89, 0x89, 0x88, + 0x8f, 0x91, 0x8e, 0x90, 0x8e, 0x8e, 0x89, 0x8a, 0x87, 0x80, 0x83, + 0x7f, 0x7a, 0x7b, 0x7c, 0x77, 0x77, 0x78, 0x7a, 0x77, 0x79, 0x7a, + 0x78, 0x7b, 0x7a, 0x7a, 0x7e, 0x7d, 0x7d, 0x7d, 0x81, 0x81, 0x7d, + 0x82, 0x85, 0x7d, 0x82, 0x81, 0x80, 0x7e, 0x81, 0x80, 0x7d, 0x82, + 0x7e, 0x80, 0x82, 0x7f, 0x80, 0x81, 0x83, 0x7f, 0x83, 0x83, 0x83, + 0x81, 0x84, 0x82, 0x83, 0x82, 0x80, 0x82, 0x82, 0x80, 0x80, 0x80, + 0x7d, 0x7b, 0x73, 0x70, 0x7a, 0x6c, 0x67, 0x74, 0x6c, 0x6e, 0x71, + 0x74, 0x79, 0x7d, 0x81, 0x84, 0x8c, 0x91, 0x8d, 0x92, 0x9b, 0x92, + 0x92, 0x94, 0x8f, 0x8d, 0x87, 0x82, 0x81, 0x7c, 0x78, 0x73, 0x75, + 0x75, 0x6e, 0x72, 0x74, 0x75, 0x76, 0x77, 0x7b, 0x80, 0x7e, 0x81, + 0x82, 0x86, 0x84, 0x83, 0x85, 0x85, 0x82, 0x80, 0x81, 0x7d, 0x7c, + 0x7a, 0x78, 0x78, 0x77, 0x78, 0x79, 0x7b, 0x7c, 0x81, 0x84, 0x84, + 0x87, 0x8a, 0x8b, 0x8b, 0x8a, 0x8b, 0x8a, 0x86, 0x85, 0x82, 0x83, + 0x80, 0x7f, 0x80, 0x7d, 0x7d, 0x7f, 0x78, 0x7a, 0x6c, 0x5b, 0x81, + 0x64, 0x4a, 0x7c, 0x61, 0x60, 0x71, 0x6c, 0x82, 0x80, 0x85, 0x90, + 0x99, 0xa4, 0x92, 0x9f, 0xae, 0x95, 0x98, 0x9c, 0x8c, 0x90, 0x7e, + 0x7a, 0x81, 0x6f, 0x6d, 0x6a, 0x70, 0x69, 0x64, 0x73, 0x71, 0x71, + 0x79, 0x78, 0x85, 0x85, 0x80, 0x8e, 0x8e, 0x8b, 0x89, 0x8c, 0x8f, + 0x84, 0x84, 0x81, 0x7c, 0x7b, 0x72, 0x70, 0x73, 0x6b, 0x6d, 0x6f, + 0x73, 0x75, 0x7a, 0x80, 0x85, 0x8a, 0x8d, 0x92, 0x93, 0x92, 0x93, + 0x93, 0x8e, 0x89, 0x88, 0x84, 0x7e, 0x7a, 0x79, 0x78, 0x75, 0x76, + 0x78, 0x7e, 0x7a, 0x7c, 0x7c, 0x83, 0x68, 0x5c, 0x95, 0x55, 0x4e, + 0x8b, 0x57, 0x69, 0x73, 0x6a, 0x8d, 0x7f, 0x84, 0x97, 0x9f, 0x9e, + 0x90, 0xa7, 0xab, 0x89, 0x9c, 0x95, 0x86, 0x8d, 0x6f, 0x7e, 0x7c, + 0x64, 0x6d, 0x6f, 0x6f, 0x69, 0x6d, 0x7d, 0x75, 0x79, 0x80, 0x83, + 0x8e, 0x83, 0x86, 0x99, 0x8a, 0x86, 0x8c, 0x8b, 0x86, 0x7a, 0x7f, + 0x7b, 0x74, 0x71, 0x69, 0x73, 0x70, 0x62, 0x71, 0x7b, 0x6e, 0x76, + 0x85, 0x84, 0x82, 0x8b, 0x91, 0x92, 0x8d, 0x91, 0x97, 0x90, 0x85, + 0x8c, 0x8d, 0x80, 0x7d, 0x82, 0x7e, 0x78, 0x77, 0x7c, 0x7a, 0x77, + 0x79, 0x81, 0x7f, 0x79, 0x80, 0x7e, 0x7c, 0x6a, 0x61, 0x7f, 0x60, + 0x4e, 0x75, 0x62, 0x65, 0x6e, 0x6e, 0x89, 0x82, 0x86, 0x9b, 0xa1, + 0xa2, 0x9b, 0xaa, 0xac, 0x95, 0x9b, 0x99, 0x8c, 0x87, 0x75, 0x7b, + 0x75, 0x63, 0x68, 0x69, 0x6a, 0x63, 0x69, 0x77, 0x75, 0x77, 0x82, + 0x87, 0x8e, 0x87, 0x8f, 0x98, 0x8c, 0x8b, 0x8c, 0x8c, 0x84, 0x79, + 0x7d, 0x78, 0x72, 0x6e, 0x6f, 0x6f, 0x6c, 0x6f, 0x70, 0x77, 0x78, + 0x79, 0x82, 0x84, 0x85, 0x86, 0x90, 0x8b, 0x88, 0x8e, 0x8c, 0x89, + 0x85, 0x87, 0x86, 0x80, 0x81, 0x80, 0x82, 0x7c, 0x7f, 0x83, 0x7f, + 0x7e, 0x80, 0x83, 0x82, 0x7f, 0x85, 0x83, 0x81, 0x7c, 0x7c, 0x71, + 0x56, 0x7c, 0x63, 0x42, 0x75, 0x5d, 0x5c, 0x6f, 0x6b, 0x83, 0x82, + 0x8b, 0x9a, 0xa3, 0xa7, 0x9e, 0xae, 0xb0, 0x97, 0xa0, 0x9a, 0x8a, + 0x88, 0x73, 0x79, 0x73, 0x62, 0x65, 0x68, 0x6a, 0x61, 0x6b, 0x78, + 0x73, 0x79, 0x83, 0x86, 0x8f, 0x87, 0x8d, 0x95, 0x8c, 0x88, 0x89, + 0x88, 0x80, 0x79, 0x7d, 0x75, 0x73, 0x6f, 0x71, 0x74, 0x71, 0x6c, + 0x7a, 0x7c, 0x74, 0x7e, 0x86, 0x86, 0x85, 0x88, 0x90, 0x89, 0x88, + 0x89, 0x8b, 0x85, 0x7f, 0x86, 0x82, 0x7e, 0x7e, 0x81, 0x80, 0x7c, + 0x81, 0x83, 0x81, 0x7f, 0x83, 0x83, 0x7e, 0x81, 0x81, 0x81, 0x7d, + 0x80, 0x7e, 0x80, 0x75, 0x72, 0x6b, 0x63, 0x73, 0x55, 0x5f, 0x73, + 0x5f, 0x70, 0x75, 0x80, 0x87, 0x89, 0x9a, 0x9e, 0xa2, 0xa1, 0xa0, + 0xa7, 0x9a, 0x91, 0x93, 0x85, 0x80, 0x75, 0x70, 0x73, 0x65, 0x66, + 0x6d, 0x6e, 0x6e, 0x72, 0x80, 0x7f, 0x82, 0x89, 0x8f, 0x90, 0x8b, + 0x8e, 0x8f, 0x88, 0x83, 0x81, 0x81, 0x7a, 0x73, 0x76, 0x75, 0x72, + 0x70, 0x74, 0x76, 0x73, 0x75, 0x7c, 0x7d, 0x79, 0x7e, 0x85, 0x81, + 0x81, 0x86, 0x89, 0x85, 0x87, 0x89, 0x89, 0x85, 0x86, 0x87, 0x85, + 0x81, 0x81, 0x82, 0x7c, 0x7c, 0x7e, 0x7e, 0x7b, 0x7b, 0x7e, 0x7c, + 0x7c, 0x7e, 0x80, 0x80, 0x7f, 0x82, 0x82, 0x81, 0x80, 0x82, 0x82, + 0x78, 0x65, 0x78, 0x6f, 0x58, 0x6b, 0x6f, 0x68, 0x6e, 0x7a, 0x81, + 0x84, 0x8c, 0x92, 0x9e, 0x9a, 0x97, 0x9f, 0x98, 0x90, 0x8d, 0x8c, + 0x81, 0x7b, 0x78, 0x76, 0x74, 0x70, 0x72, 0x79, 0x77, 0x78, 0x7f, + 0x83, 0x80, 0x84, 0x88, 0x87, 0x85, 0x83, 0x84, 0x82, 0x7e, 0x7b, + 0x7f, 0x7b, 0x76, 0x7b, 0x79, 0x77, 0x77, 0x78, 0x78, 0x76, 0x78, + 0x7c, 0x7b, 0x7a, 0x7f, 0x82, 0x82, 0x84, 0x88, 0x8a, 0x88, 0x8a, + 0x8b, 0x8a, 0x86, 0x84, 0x85, 0x80, 0x7d, 0x7c, 0x7d, 0x79, 0x79, + 0x7a, 0x7d, 0x7b, 0x7d, 0x80, 0x80, 0x81, 0x81, 0x83, 0x84, 0x80, + 0x83, 0x80, 0x7f, 0x7e, 0x7d, 0x7d, 0x7a, 0x7f, 0x71, 0x66, 0x7f, + 0x68, 0x62, 0x73, 0x71, 0x6f, 0x75, 0x80, 0x7f, 0x8a, 0x89, 0x8f, + 0x99, 0x90, 0x92, 0x96, 0x91, 0x89, 0x8d, 0x88, 0x82, 0x82, 0x7d, + 0x7e, 0x7d, 0x78, 0x7c, 0x7c, 0x78, 0x78, 0x7e, 0x7a, 0x79, 0x7c, + 0x7d, 0x7e, 0x7c, 0x7e, 0x80, 0x80, 0x80, 0x81, 0x83, 0x7f, 0x80, + 0x81, 0x7d, 0x7c, 0x7b, 0x7c, 0x79, 0x7a, 0x7a, 0x7d, 0x7c, 0x7e, + 0x80, 0x82, 0x82, 0x84, 0x84, 0x85, 0x84, 0x83, 0x84, 0x82, 0x81, + 0x7f, 0x7f, 0x7c, 0x7d, 0x7d, 0x7d, 0x7c, 0x7e, 0x7e, 0x7f, 0x80, + 0x7e, 0x80, 0x81, 0x80, 0x7f, 0x80, 0x7e, 0x7f, 0x7e, 0x7c, 0x7d, + 0x7d, 0x7b, 0x7c, 0x7c, 0x7c, 0x7c, 0x7f, 0x7e, 0x7f, 0x80, 0x81, + 0x81, 0x7e, 0x7e, 0x80, 0x7e, 0x7d, 0x7f, 0x80, 0x7d, 0x80, 0x80, + 0x7f, 0x7f, 0x80, 0x7f, 0x81, 0x7f, 0x81, 0x81, 0x82, 0x82, 0x84, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x82, 0x81, 0x81, 0x80, 0x7f, 0x7d, + 0x80, 0x7e, 0x7d, 0x7c, 0x7f, 0x7d, 0x7d, 0x7f, 0x7e, 0x7f, 0x7f, + 0x7e, 0x7e, 0x7d, 0x7e, 0x7e, 0x7d, 0x7e, 0x7e, 0x7f, 0x7d, 0x7e, + 0x7f, 0x80, 0x7e, 0x80, 0x7f, 0x80, 0x81, 0x80, 0x81, 0x81, 0x81, + 0x80, 0x81, 0x81, 0x7f, 0x81, 0x7f, 0x7f, 0x80, 0x7e, 0x7f, 0x7e, + 0x7d, 0x7d, 0x7e, 0x7b, 0x7b, 0x7d, 0x7b, 0x7a, 0x7c, 0x7b, 0x7c, + 0x7c, 0x7e, 0x7d, 0x80, 0x7f, 0x81, 0x81, 0x82, 0x81, 0x83, 0x82, + 0x80, 0x82, 0x81, 0x81, 0x80, 0x81, 0x81, 0x82, 0x80, 0x81, 0x82, + 0x80, 0x81, 0x80, 0x82, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, + 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x81, 0x80, 0x81, 0x80, 0x81, 0x7f, + 0x7f, 0x7f, 0x7e, 0x7e, 0x7d, 0x7e, 0x7e, 0x7c, 0x7e, 0x7e, 0x7d, + 0x7e, 0x7c, 0x7e, 0x7f, 0x7e, 0x7d, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, + 0x80, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x80, + 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, 0x7e, 0x7d, + 0x7e, 0x7c, 0x7c, 0x7c, 0x7d, 0x7c, 0x7d, 0x7d, 0x7f, 0x7e, 0x80, + 0x81, 0x82, 0x81, 0x83, 0x83, 0x83, 0x83, 0x83, 0x82, 0x83, 0x81, + 0x82, 0x80, 0x80, 0x7e, 0x7f, 0x7e, 0x7c, 0x7e, 0x7d, 0x7e, 0x7d, + 0x7e, 0x7f, 0x7f, 0x80, 0x81, 0x80, 0x81, 0x81, 0x82, 0x81, 0x81, + 0x80, + }, + { // 5 + 0x7f, 0x7f, 0x7f, 0x7c, 0x7a, 0x7c, 0x7d, 0x7a, 0x7b, 0x81, 0x83, + 0x82, 0x85, 0x87, 0x87, 0x88, 0x87, 0x84, 0x83, 0x84, 0x81, 0x7c, + 0x7c, 0x7f, 0x7d, 0x7a, 0x7c, 0x7f, 0x7e, 0x7e, 0x81, 0x82, 0x82, + 0x83, 0x82, 0x82, 0x83, 0x81, 0x7e, 0x7e, 0x7f, 0x7c, 0x7b, 0x7c, + 0x7c, 0x7b, 0x7c, 0x7d, 0x7d, 0x7e, 0x7f, 0x7f, 0x7f, 0x80, 0x80, + 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x81, 0x82, 0x81, 0x82, 0x81, 0x82, 0x82, 0x82, 0x82, + 0x81, 0x82, 0x81, 0x83, 0x83, 0x83, 0x83, 0x83, 0x85, 0x84, 0x84, + 0x85, 0x85, 0x83, 0x78, 0x5c, 0x68, 0x7a, 0x57, 0x5d, 0x6f, 0x69, + 0x7e, 0x81, 0x7e, 0x96, 0xa6, 0x9f, 0x99, 0xa1, 0xa2, 0x94, 0x89, + 0x7e, 0x74, 0x79, 0x6c, 0x5b, 0x69, 0x70, 0x6f, 0x73, 0x7e, 0x8b, + 0x92, 0x90, 0x91, 0x9a, 0x95, 0x89, 0x84, 0x82, 0x7b, 0x74, 0x6e, + 0x71, 0x7a, 0x77, 0x7d, 0x8a, 0x8d, 0x91, 0x98, 0x99, 0x98, 0x92, + 0x54, 0x4f, 0x83, 0x49, 0x34, 0x5b, 0x52, 0x70, 0x82, 0x74, 0x95, + 0xbe, 0xb8, 0xa4, 0xa3, 0xaf, 0xa2, 0x7b, 0x6d, 0x62, 0x64, 0x67, + 0x46, 0x56, 0x7c, 0x81, 0x89, 0x8d, 0xa2, 0xb5, 0xa7, 0x94, 0x89, + 0x8f, 0x7f, 0x5b, 0x56, 0x60, 0x62, 0x59, 0x66, 0x80, 0x90, 0x95, + 0x96, 0xa5, 0xaa, 0x9c, 0x8a, 0x87, 0x87, 0x78, 0x6d, 0x6d, 0x76, + 0x7a, 0x7e, 0x85, 0x8b, 0x81, 0x50, 0x6a, 0x8b, 0x53, 0x5d, 0x72, + 0x6d, 0x8b, 0x8b, 0x7f, 0x99, 0xb0, 0x9f, 0x88, 0x87, 0x92, 0x81, + 0x66, 0x68, 0x67, 0x77, 0x7d, 0x68, 0x80, 0x9d, 0x98, 0x94, 0x8e, + 0x95, 0x96, 0x7e, 0x70, 0x6c, 0x72, 0x69, 0x59, 0x68, 0x7e, 0x81, + 0x7f, 0x8a, 0x98, 0x97, 0x8f, 0x87, 0x8b, 0x89, 0x7a, 0x74, 0x7b, + 0x81, 0x7e, 0x7f, 0x87, 0x8e, 0x91, 0x91, 0x92, 0x8f, 0x7f, 0x40, + 0x38, 0x78, 0x52, 0x3b, 0x72, 0x7c, 0x96, 0xb3, 0x98, 0x9d, 0xc4, + 0xa8, 0x75, 0x70, 0x6e, 0x67, 0x59, 0x4f, 0x65, 0x86, 0x9a, 0x90, + 0x94, 0xb5, 0xaf, 0x94, 0x82, 0x71, 0x73, 0x68, 0x50, 0x58, 0x71, + 0x7e, 0x82, 0x8c, 0x99, 0xa1, 0x97, 0x83, 0x7d, 0x7d, 0x6b, 0x61, + 0x6c, 0x7c, 0x84, 0x85, 0x8e, 0x97, 0x97, 0x8b, 0x81, 0x85, 0x85, + 0x7b, 0x79, 0x83, 0x89, 0x83, 0x81, 0x70, 0x41, 0x5c, 0x86, 0x53, + 0x5d, 0x89, 0x86, 0x9a, 0xa3, 0x8d, 0x92, 0xa8, 0x8a, 0x65, 0x70, + 0x72, 0x6d, 0x6f, 0x6f, 0x80, 0x96, 0x9d, 0x90, 0x8c, 0x9a, 0x8e, + 0x78, 0x6f, 0x69, 0x72, 0x75, 0x6f, 0x7b, 0x8b, 0x93, 0x8e, 0x85, + 0x86, 0x83, 0x6f, 0x65, 0x6d, 0x74, 0x77, 0x7e, 0x8b, 0x97, 0x9a, + 0x8e, 0x85, 0x89, 0x7f, 0x72, 0x72, 0x7a, 0x82, 0x84, 0x86, 0x8d, + 0x95, 0x92, 0x8d, 0x84, 0x7e, 0x56, 0x22, 0x5c, 0x79, 0x53, 0x78, + 0x96, 0x9f, 0xb9, 0xac, 0x85, 0x86, 0x96, 0x6b, 0x4b, 0x5f, 0x6c, + 0x7d, 0x88, 0x89, 0x9e, 0xb0, 0xa7, 0x86, 0x73, 0x7c, 0x6f, 0x5e, + 0x5d, 0x67, 0x84, 0x92, 0x90, 0x96, 0x9c, 0x99, 0x84, 0x69, 0x64, + 0x6c, 0x66, 0x62, 0x75, 0x8d, 0x96, 0x96, 0x93, 0x93, 0x91, 0x7c, + 0x6d, 0x74, 0x79, 0x76, 0x79, 0x84, 0x91, 0x8f, 0x8b, 0x87, 0x89, + 0x8f, 0x84, 0x7f, 0x7a, 0x75, 0x4d, 0x2b, 0x6f, 0x8a, 0x67, 0x87, + 0x9c, 0x9f, 0xb0, 0x99, 0x70, 0x78, 0x8b, 0x66, 0x54, 0x6d, 0x80, + 0x90, 0x8f, 0x8d, 0x99, 0xa2, 0x97, 0x73, 0x68, 0x79, 0x73, 0x6b, + 0x6e, 0x78, 0x93, 0x97, 0x8d, 0x8b, 0x8c, 0x89, 0x76, 0x64, 0x67, + 0x74, 0x7a, 0x7a, 0x81, 0x90, 0x94, 0x8c, 0x7f, 0x7d, 0x7f, 0x75, + 0x72, 0x7a, 0x86, 0x89, 0x86, 0x89, 0x8d, 0x89, 0x81, 0x7c, 0x81, + 0x86, 0x81, 0x82, 0x89, 0x8c, 0x84, 0x7c, 0x54, 0x2b, 0x70, 0x85, + 0x53, 0x7b, 0x9f, 0x9f, 0xaf, 0xa0, 0x7a, 0x87, 0x92, 0x63, 0x50, + 0x67, 0x7c, 0x83, 0x82, 0x90, 0x9e, 0xa8, 0x9f, 0x78, 0x75, 0x81, + 0x6e, 0x65, 0x67, 0x79, 0x8f, 0x8e, 0x8c, 0x8e, 0x93, 0x8b, 0x74, + 0x67, 0x6b, 0x6f, 0x6f, 0x78, 0x87, 0x90, 0x96, 0x90, 0x86, 0x83, + 0x7a, 0x70, 0x6e, 0x77, 0x7f, 0x81, 0x87, 0x8d, 0x90, 0x8c, 0x84, + 0x81, 0x80, 0x7e, 0x7c, 0x7c, 0x7f, 0x86, 0x89, 0x89, 0x89, 0x86, + 0x75, 0x38, 0x3f, 0x8a, 0x6a, 0x5b, 0x92, 0x9b, 0xa6, 0xb1, 0x88, + 0x7d, 0x96, 0x79, 0x55, 0x56, 0x72, 0x82, 0x7a, 0x8a, 0x99, 0xa6, + 0xad, 0x86, 0x77, 0x84, 0x75, 0x65, 0x5d, 0x6b, 0x85, 0x87, 0x88, + 0x93, 0x9d, 0x9c, 0x85, 0x72, 0x74, 0x71, 0x67, 0x63, 0x68, 0x80, + 0x91, 0x8c, 0x8b, 0x96, 0x91, 0x7d, 0x72, 0x71, 0x74, 0x73, 0x74, + 0x7e, 0x8f, 0x8f, 0x88, 0x8c, 0x8f, 0x86, 0x7c, 0x7b, 0x7d, 0x7f, + 0x7b, 0x7d, 0x86, 0x8c, 0x8c, 0x8c, 0x8b, 0x86, 0x6f, 0x32, 0x44, + 0x81, 0x55, 0x56, 0x90, 0x96, 0xac, 0xad, 0x8c, 0x99, 0xa0, 0x7a, + 0x58, 0x5c, 0x77, 0x6c, 0x6a, 0x83, 0x93, 0xae, 0xa3, 0x8a, 0x98, + 0x95, 0x79, 0x66, 0x60, 0x6f, 0x72, 0x6c, 0x78, 0x8c, 0x9c, 0x91, + 0x85, 0x8d, 0x88, 0x79, 0x68, 0x63, 0x72, 0x6c, 0x6f, 0x87, 0x8c, + 0x91, 0x93, 0x8d, 0x89, 0x84, 0x75, 0x70, 0x75, 0x73, 0x76, 0x81, + 0x87, 0x8a, 0x8e, 0x8d, 0x8b, 0x86, 0x7d, 0x79, 0x7a, 0x78, 0x77, + 0x7c, 0x80, 0x84, 0x86, 0x88, 0x8b, 0x8c, 0x89, 0x80, 0x75, 0x4b, + 0x48, 0x7d, 0x5c, 0x53, 0x8a, 0x8b, 0x99, 0xa3, 0x92, 0xa4, 0xa5, + 0x88, 0x70, 0x72, 0x7c, 0x63, 0x5f, 0x73, 0x7c, 0x8e, 0x8a, 0x88, + 0xa2, 0x9d, 0x8c, 0x86, 0x81, 0x7e, 0x6d, 0x63, 0x6a, 0x74, 0x78, + 0x74, 0x84, 0x94, 0x90, 0x8e, 0x8d, 0x8c, 0x87, 0x76, 0x6f, 0x74, + 0x6f, 0x64, 0x74, 0x7e, 0x7d, 0x86, 0x89, 0x8c, 0x8f, 0x88, 0x82, + 0x81, 0x7b, 0x76, 0x79, 0x79, 0x7b, 0x80, 0x84, 0x86, 0x85, 0x87, + 0x89, 0x86, 0x80, 0x7f, 0x80, 0x7f, 0x7c, 0x7c, 0x7f, 0x80, 0x7f, + 0x83, 0x85, 0x87, 0x83, 0x7f, 0x6e, 0x51, 0x75, 0x73, 0x4d, 0x74, + 0x7b, 0x80, 0x94, 0x85, 0x9b, 0xa8, 0x96, 0x91, 0x8d, 0x8e, 0x7c, + 0x6d, 0x70, 0x6d, 0x73, 0x6d, 0x72, 0x89, 0x86, 0x8a, 0x95, 0x96, + 0x98, 0x8c, 0x84, 0x83, 0x7b, 0x6f, 0x66, 0x6e, 0x71, 0x6d, 0x74, + 0x7d, 0x89, 0x8c, 0x89, 0x90, 0x93, 0x8d, 0x84, 0x80, 0x7a, 0x75, + 0x73, 0x6d, 0x72, 0x76, 0x77, 0x7b, 0x80, 0x83, 0x87, 0x88, 0x88, + 0x8a, 0x8a, 0x88, 0x84, 0x80, 0x7f, 0x7c, 0x76, 0x76, 0x78, 0x7a, + 0x7e, 0x80, 0x87, 0x8b, 0x8b, 0x8a, 0x8a, 0x88, 0x83, 0x7e, 0x7c, + 0x7a, 0x78, 0x79, 0x77, 0x77, 0x60, 0x70, 0x83, 0x5b, 0x73, 0x7e, + 0x6f, 0x8a, 0x7a, 0x86, 0x9f, 0x8e, 0x91, 0x96, 0x97, 0x8d, 0x83, + 0x83, 0x7c, 0x7e, 0x70, 0x6f, 0x7f, 0x74, 0x78, 0x7d, 0x80, 0x88, + 0x80, 0x83, 0x8a, 0x8a, 0x86, 0x83, 0x8a, 0x85, 0x81, 0x7d, 0x79, + 0x7a, 0x71, 0x6f, 0x74, 0x74, 0x77, 0x79, 0x81, 0x88, 0x87, 0x88, + 0x8d, 0x8a, 0x86, 0x81, 0x7e, 0x7d, 0x76, 0x75, 0x79, 0x7a, 0x7a, + 0x7e, 0x81, 0x83, 0x84, 0x85, 0x85, 0x83, 0x83, 0x84, 0x82, 0x81, + 0x83, 0x83, 0x82, 0x80, 0x7f, 0x82, 0x7f, 0x7b, 0x7c, 0x7d, 0x7c, + 0x7a, 0x7e, 0x82, 0x83, 0x83, 0x86, 0x86, 0x85, 0x7d, 0x73, 0x7d, + 0x74, 0x69, 0x72, 0x6d, 0x71, 0x76, 0x75, 0x80, 0x85, 0x84, 0x8b, + 0x8f, 0x8d, 0x8e, 0x8b, 0x8a, 0x8c, 0x86, 0x85, 0x88, 0x84, 0x83, + 0x84, 0x82, 0x81, 0x7e, 0x7b, 0x7a, 0x79, 0x77, 0x78, 0x79, 0x7a, + 0x7c, 0x7c, 0x7f, 0x80, 0x80, 0x80, 0x81, 0x80, 0x81, 0x81, 0x81, + 0x82, 0x82, 0x82, 0x81, 0x82, 0x80, 0x7e, 0x7e, 0x7c, 0x7b, 0x7c, + 0x7c, 0x7e, 0x80, 0x82, 0x82, 0x82, 0x82, 0x80, 0x80, 0x7e, 0x7d, + 0x7e, 0x7e, 0x7f, 0x82, 0x83, 0x83, 0x84, 0x83, 0x82, 0x82, 0x80, + 0x7e, 0x7f, 0x7e, 0x7c, 0x7c, 0x7d, 0x7f, 0x7f, 0x7e, 0x7f, 0x7f, + 0x7e, 0x7e, 0x7d, 0x7f, 0x80, 0x80, 0x80, 0x81, 0x82, 0x81, 0x7f, + 0x7f, 0x7e, 0x7e, 0x7e, 0x7d, 0x7e, 0x80, 0x7f, 0x81, 0x7f, 0x7f, + 0x84, 0x81, 0x7e, 0x7e, 0x80, 0x81, 0x81, 0x80, 0x80, 0x83, 0x82, + 0x81, 0x82, 0x82, 0x82, 0x81, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x80, + 0x80, 0x80, 0x81, 0x82, 0x81, 0x80, 0x7f, 0x7e, 0x7d, 0x7b, 0x7a, + 0x7b, 0x7c, 0x7c, 0x7d, 0x7f, 0x81, 0x81, 0x82, 0x81, 0x81, 0x81, + 0x7f, 0x7d, 0x7f, 0x7e, 0x7e, 0x7f, 0x80, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x80, 0x80, 0x81, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, + 0x7e, 0x7c, 0x7d, 0x7e, 0x7d, 0x7f, 0x7f, 0x80, 0x82, 0x82, 0x82, + 0x81, 0x7f, 0x80, 0x7e, 0x7d, 0x7d, 0x7e, 0x80, 0x80, 0x80, 0x82, + 0x83, 0x82, 0x81, 0x80, 0x80, 0x81, 0x7f, 0x7d, 0x7f, 0x80, 0x7f, + 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x81, 0x82, 0x82, 0x82, 0x81, 0x81, 0x80, 0x7e, 0x7d, 0x7d, 0x7d, + 0x7d, 0x7e, 0x7f, 0x81, 0x84, 0x84, 0x84, 0x83, 0x83, 0x80, 0x7d, + 0x7b, 0x7b, 0x7a, 0x7a, 0x7c, 0x7f, 0x81, 0x82, 0x82, 0x83, 0x83, + 0x82, 0x80, 0x7f, 0x7d, 0x7d, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x81, + 0x81, 0x81, 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x81, 0x81, 0x81, + 0x81, 0x80, 0x7e, 0x7d, 0x7d, 0x7d, 0x7d, 0x7e, 0x7f, 0x80, 0x81, + 0x82, 0x82, 0x81, 0x80, 0x7f, 0x7d, 0x7d, 0x7d, 0x7e, 0x7e, 0x80, + 0x82, 0x82, 0x82, 0x82, 0x81, 0x80, 0x7f, 0x7e, 0x7e, 0x7e, 0x7f, + 0x7f, 0x80, 0x81, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7e, 0x7e, 0x7e, + 0x7f, 0x7f, 0x80, 0x80, 0x81, 0x81, 0x80, 0x80, 0x7f, 0x7e, 0x7e, + 0x7e, 0x7e, 0x7f, 0x7e, 0x7f, 0x80, 0x80, 0x80, 0x81, 0x81, 0x81, + 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, 0x7f, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x82, 0x81, 0x80, 0x80, 0x80, 0x80, + 0x7f, 0x7e, 0x7f, 0x80, 0x7f, 0x7e, 0x7e, 0x80, 0x80, 0x7f, 0x7f, + 0x80, 0x80, 0x80, 0x7e, 0x7f, 0x80, 0x80, 0x7e, 0x7f, 0x80, 0x81, + 0x80, 0x80, 0x80, 0x81, 0x80, 0x7e, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, + 0x80, 0x81, 0x81, 0x80, 0x80, 0x81, 0x80, 0x7e, 0x7d, 0x7d, 0x7d, + 0x7d, 0x7d, 0x7e, 0x80, 0x81, 0x81, 0x81, 0x82, 0x82, 0x80, 0x7f, + 0x7f, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x80, 0x81, 0x81, 0x81, + 0x80, 0x7f, 0x80, 0x7f, 0x7e, 0x7e, 0x7f, 0x80, 0x81, 0x80, 0x80, + 0x81, 0x81, 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x80, 0x81, + 0x81, 0x82, 0x82, 0x82, 0x80, 0x7f, 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, + 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, + 0x80, 0x81, 0x81, 0x80, 0x80, 0x81, 0x80, 0x80, 0x80, 0x7f, 0x7f, + 0x7f, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x80, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x80, 0x7f, 0x7e, 0x7e, 0x7d, 0x7d, 0x7d, 0x7d, 0x7f, 0x81, + 0x81, 0x82, 0x83, 0x84, 0x83, 0x81, 0x80, 0x7f, 0x7e, 0x7c, 0x7c, + 0x7d, 0x7e, 0x7f, 0x7f, 0x81, 0x82, 0x82, 0x81, 0x80, 0x80, 0x7f, + 0x7e, 0x7d, 0x7e, 0x7f, 0x7f, 0x7f, 0x80, 0x81, 0x81, 0x80, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x81, 0x80, + 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x7f, + 0x80, 0x7f, 0x7e, 0x7e, 0x7f, 0x7f, 0x80, 0x80, 0x81, 0x81, 0x81, + 0x80, 0x80, 0x7f, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, + 0x7f, 0x80, 0x81, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x80, + 0x80, 0x7f, 0x7e, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x7f, + 0x7f, 0x80, 0x7f, 0x7f, 0x7e, 0x7f, 0x80, 0x80, 0x80, 0x81, 0x82, + 0x81, 0x80, 0x80, 0x80, 0x7f, 0x7e, 0x7d, 0x7e, 0x7e, 0x7e, 0x7e, + 0x80, 0x81, 0x82, 0x81, 0x80, 0x81, 0x81, 0x7f, 0x7e, 0x7e, 0x7f, + 0x7e, 0x7f, 0x80, 0x81, 0x81, 0x80, 0x80, 0x80, 0x81, 0x7d, 0x7c, + 0x7f, 0x80, 0x81, 0x80, 0x81, 0x80, 0x80, 0x81, 0x81, 0x7f, 0x7f, + 0x7f, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x80, 0x81, 0x81, 0x80, 0x80, + 0x80, 0x7f, 0x7f, 0x7e, 0x7f, 0x7e, 0x7f, 0x7f, 0x7f, 0x80, 0x81, + 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, + 0x80, 0x80, 0x81, 0x81, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x7f, + 0x7e, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, + 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, + 0x80, 0x81, 0x81, 0x81, 0x81, 0x80, 0x80, 0x7f, 0x7e, 0x7d, 0x7d, + 0x7e, 0x7f, 0x80, 0x80, 0x81, 0x81, 0x82, 0x81, 0x81, 0x80, 0x7f, + 0x7e, 0x7e, 0x7e, 0x7d, 0x7f, 0x7f, 0x80, 0x81, 0x80, 0x82, 0x81, + 0x80, 0x80, 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, 0x80, 0x7f, 0x80, 0x81, + 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x81, 0x80, 0x7f, + 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7e, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x81, 0x7f, 0x7e, 0x80, 0x7e, 0x7f, 0x80, 0x7e, 0x80, 0x7f, 0x80, + 0x80, 0x80, 0x7f, 0x80, 0x7e, 0x7f, 0x7f, 0x7e, 0x80, 0x80, 0x7f, + 0x81, 0x7f, 0x81, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7e, + 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x81, 0x80, 0x80, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7e, 0x7e, 0x7e, 0x81, 0x80, 0x80, 0x80, 0x80, 0x81, 0x7f, + 0x7e, 0x7f, 0x7f, 0x7e, 0x7f, 0x7f, 0x80, 0x81, 0x7f, 0x80, 0x80, + 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7e, 0x80, 0x81, 0x7e, 0x82, + 0x7e, 0x7e, 0x82, 0x7c, 0x80, 0x82, 0x7f, 0x80, 0x80, 0x7d, 0x7f, + 0x80, 0x7e, 0x80, 0x80, 0x80, 0x81, 0x7f, 0x80, 0x81, 0x7e, 0x7f, + 0x7f, 0x7d, 0x80, 0x7e, 0x7f, 0x80, 0x7f, 0x81, 0x7f, 0x7f, 0x82, + 0x80, 0x7f, 0x82, 0x7e, 0x7f, 0x7f, 0x7e, 0x80, 0x7f, 0x7f, 0x80, + 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x81, 0x7f, 0x80, 0x80, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7e, 0x80, 0x81, 0x7f, 0x80, + 0x80, 0x80, 0x81, 0x7e, 0x80, 0x7f, 0x7f, 0x7f, 0x7e, 0x80, 0x7f, + 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x81, 0x7e, + 0x81, 0x7f, 0x7e, 0x81, 0x7f, 0x7e, 0x81, 0x7e, 0x7f, 0x81, 0x7d, + 0x80, 0x82, 0x7e, 0x81, 0x81, 0x7c, 0x83, 0x7f, 0x7e, 0x7f, 0x7e, + 0x80, 0x7e, 0x7f, 0x81, 0x80, 0x81, 0x81, 0x7f, 0x81, 0x7f, 0x7f, + 0x7e, 0x80, 0x7d, 0x81, 0x7f, 0x7f, 0x83, 0x7d, 0x80, 0x81, 0x7e, + 0x7f, 0x80, 0x7c, 0x81, 0x7f, 0x7f, 0x81, 0x7f, 0x81, 0x7f, 0x80, + 0x7f, 0x7f, 0x80, 0x7f, 0x7e, 0x7f, 0x80, 0x81, 0x80, 0x7f, 0x81, + 0x82, 0x7d, 0x80, 0x80, 0x7d, 0x82, 0x7e, 0x7e, 0x81, 0x7f, 0x80, + 0x80, 0x7f, 0x81, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7e, 0x81, + 0x7f, 0x7f, 0x81, 0x7e, 0x82, 0x80, 0x80, 0x81, 0x7f, 0x7f, 0x7f, + 0x80, 0x7e, 0x7f, 0x80, 0x7e, 0x81, 0x7f, 0x7f, 0x80, 0x80, 0x80, + 0x7f, 0x81, 0x7f, 0x80, 0x7f, 0x7e, 0x81, 0x7e, 0x80, 0x7f, 0x7f, + 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, + 0x7f, 0x80, 0x7f, 0x81, 0x7f, 0x80, 0x81, 0x7f, 0x80, 0x7f, 0x7e, + 0x7f, 0x80, 0x7d, 0x81, 0x7f, 0x7f, 0x82, 0x7f, 0x80, 0x82, 0x7e, + 0x7f, 0x80, 0x7d, 0x80, 0x7f, 0x7e, 0x81, 0x81, 0x7f, 0x82, 0x7f, + 0x80, 0x81, 0x7d, 0x80, 0x7d, 0x80, 0x80, 0x7e, 0x81, 0x81, 0x7f, + 0x80, 0x80, 0x7f, 0x81, 0x7d, 0x7e, 0x82, 0x7e, 0x7f, 0x81, 0x7f, + 0x82, 0x81, 0x7d, 0x82, 0x7f, 0x7f, 0x80, 0x7d, 0x80, 0x82, 0x7e, + 0x81, 0x80, 0x7f, 0x81, 0x7e, 0x80, 0x7f, 0x7e, 0x81, 0x7e, 0x7f, + 0x81, 0x7e, 0x80, 0x81, 0x7d, 0x80, 0x7f, 0x7e, 0x80, 0x80, 0x80, + 0x7f, 0x81, 0x80, 0x80, 0x81, 0x7f, 0x80, 0x81, 0x7f, 0x7f, 0x80, + 0x7d, 0x80, 0x7e, 0x7e, 0x81, 0x7e, 0x81, 0x7f, 0x80, 0x81, 0x80, + 0x80, 0x80, 0x7f, 0x7e, 0x81, 0x7e, 0x80, 0x7f, 0x81, 0x80, 0x7f, + 0x82, 0x7d, 0x80, 0x80, 0x7d, 0x7f, 0x80, 0x7d, 0x81, 0x81, 0x7e, + 0x82, 0x80, 0x80, 0x81, 0x7e, 0x80, 0x80, 0x7e, 0x80, 0x7e, 0x80, + 0x80, 0x7e, 0x80, 0x81, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x7f, + 0x7f, 0x80, 0x80, 0x7e, 0x81, 0x7f, 0x7f, 0x81, 0x7e, 0x7f, 0x7f, + 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x81, 0x7e, 0x80, 0x81, 0x7f, 0x80, + 0x80, 0x80, 0x7f, 0x81, 0x7d, 0x7f, 0x80, 0x7e, 0x80, 0x7f, 0x81, + 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x7e, 0x80, 0x80, 0x7f, + 0x80, 0x81, 0x80, 0x80, 0x80, 0x7f, 0x7e, 0x80, 0x7e, 0x7f, 0x80, + 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x81, 0x7f, 0x80, 0x80, 0x7f, 0x81, + 0x7f, 0x7f, 0x80, 0x80, 0x7e, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x80, + 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x80, + }, + { // 6 + 0x80, 0x80, 0x80, 0x7f, 0x7e, 0x80, 0x81, 0x80, 0x7f, 0x7e, 0x7f, + 0x81, 0x80, 0x7f, 0x7e, 0x7f, 0x81, 0x80, 0x7f, 0x7e, 0x7f, 0x81, + 0x81, 0x7f, 0x7e, 0x7f, 0x81, 0x81, 0x7f, 0x7e, 0x7e, 0x81, 0x81, + 0x80, 0x7e, 0x7d, 0x80, 0x82, 0x81, 0x7d, 0x7d, 0x80, 0x83, 0x80, + 0x7d, 0x7d, 0x81, 0x82, 0x7f, 0x7d, 0x7f, 0x82, 0x81, 0x7e, 0x7e, + 0x80, 0x82, 0x80, 0x7d, 0x7e, 0x82, 0x82, 0x7f, 0x7c, 0x7f, 0x82, + 0x81, 0x7e, 0x7d, 0x80, 0x82, 0x80, 0x7e, 0x7e, 0x80, 0x81, 0x80, + 0x7f, 0x7f, 0x7f, 0x80, 0x81, 0x7f, 0x7e, 0x80, 0x81, 0x80, 0x7e, + 0x7e, 0x80, 0x81, 0x80, 0x7e, 0x7e, 0x81, 0x81, 0x7f, 0x7d, 0x7e, + 0x81, 0x82, 0x80, 0x7c, 0x7d, 0x82, 0x83, 0x7e, 0x7c, 0x7f, 0x83, + 0x81, 0x7d, 0x7e, 0x80, 0x81, 0x80, 0x7f, 0x7f, 0x80, 0x81, 0x80, + 0x7f, 0x7e, 0x80, 0x82, 0x7f, 0x7d, 0x7f, 0x81, 0x80, 0x80, 0x7e, + 0x7e, 0x80, 0x82, 0x7f, 0x7e, 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x80, + 0x7e, 0x7f, 0x82, 0x81, 0x7c, 0x7e, 0x82, 0x80, 0x7d, 0x80, 0x81, + 0x7d, 0x7f, 0x83, 0x80, 0x7d, 0x7d, 0x82, 0x84, 0x7e, 0x7b, 0x80, + 0x82, 0x80, 0x7e, 0x80, 0x7f, 0x7e, 0x80, 0x83, 0x81, 0x7a, 0x7d, + 0x85, 0x82, 0x7c, 0x7c, 0x81, 0x82, 0x7e, 0x80, 0x80, 0x7d, 0x7e, + 0x83, 0x83, 0x7a, 0x7b, 0x84, 0x85, 0x7c, 0x7b, 0x81, 0x82, 0x80, + 0x7e, 0x7f, 0x80, 0x7e, 0x82, 0x83, 0x7b, 0x7c, 0x84, 0x82, 0x7d, + 0x7e, 0x7e, 0x83, 0x81, 0x7e, 0x7d, 0x7f, 0x84, 0x82, 0x7c, 0x79, + 0x82, 0x86, 0x7f, 0x7a, 0x7c, 0x85, 0x85, 0x7c, 0x7c, 0x7e, 0x81, + 0x84, 0x81, 0x7b, 0x79, 0x84, 0x86, 0x7d, 0x7b, 0x7d, 0x81, 0x84, + 0x81, 0x79, 0x7b, 0x87, 0x84, 0x78, 0x7e, 0x83, 0x81, 0x7f, 0x80, + 0x7d, 0x7d, 0x87, 0x84, 0x77, 0x78, 0x88, 0x87, 0x7a, 0x78, 0x82, + 0x87, 0x7f, 0x7c, 0x7d, 0x83, 0x82, 0x7e, 0x7e, 0x7f, 0x80, 0x82, + 0x7f, 0x7b, 0x7f, 0x86, 0x80, 0x76, 0x7f, 0x89, 0x83, 0x77, 0x79, + 0x85, 0x85, 0x7e, 0x7c, 0x80, 0x80, 0x80, 0x82, 0x80, 0x7a, 0x80, + 0x84, 0x7e, 0x7b, 0x80, 0x89, 0x7a, 0x75, 0x88, 0x86, 0x7b, 0x7c, + 0x7e, 0x84, 0x82, 0x7e, 0x80, 0x7c, 0x7e, 0x85, 0x83, 0x7a, 0x7d, + 0x81, 0x83, 0x81, 0x7c, 0x7e, 0x7f, 0x80, 0x83, 0x7f, 0x7b, 0x82, + 0x81, 0x7e, 0x7d, 0x82, 0x83, 0x7c, 0x7e, 0x7e, 0x81, 0x85, 0x7f, + 0x78, 0x7e, 0x84, 0x84, 0x7f, 0x79, 0x7c, 0x87, 0x84, 0x7c, 0x7d, + 0x7c, 0x81, 0x86, 0x81, 0x79, 0x7c, 0x84, 0x83, 0x81, 0x7a, 0x7c, + 0x84, 0x83, 0x7c, 0x80, 0x7d, 0x7d, 0x85, 0x84, 0x7e, 0x76, 0x7e, + 0x86, 0x87, 0x7d, 0x75, 0x81, 0x85, 0x83, 0x7f, 0x7d, 0x7b, 0x80, + 0x84, 0x7f, 0x80, 0x7f, 0x7d, 0x80, 0x83, 0x7e, 0x80, 0x81, 0x7c, + 0x7b, 0x86, 0x85, 0x7a, 0x7d, 0x7b, 0x81, 0x8a, 0x7d, 0x76, 0x7f, + 0x87, 0x84, 0x7a, 0x7a, 0x82, 0x88, 0x7e, 0x73, 0x85, 0x88, 0x7d, + 0x7a, 0x7c, 0x85, 0x82, 0x7e, 0x7c, 0x7e, 0x83, 0x7f, 0x83, 0x7b, + 0x7a, 0x86, 0x81, 0x7d, 0x79, 0x83, 0x86, 0x7b, 0x7c, 0x81, 0x80, + 0x7c, 0x84, 0x83, 0x7f, 0x78, 0x79, 0x8d, 0x86, 0x77, 0x78, 0x7f, + 0x8b, 0x80, 0x78, 0x7f, 0x7e, 0x84, 0x87, 0x7c, 0x71, 0x84, 0x8b, + 0x80, 0x79, 0x76, 0x87, 0x86, 0x7e, 0x7b, 0x7e, 0x83, 0x7f, 0x82, + 0x80, 0x77, 0x82, 0x87, 0x7e, 0x7d, 0x7b, 0x84, 0x80, 0x7e, 0x84, + 0x76, 0x82, 0x88, 0x79, 0x80, 0x80, 0x7e, 0x83, 0x7c, 0x7f, 0x86, + 0x7f, 0x76, 0x7f, 0x86, 0x82, 0x85, 0x79, 0x77, 0x83, 0x85, 0x84, + 0x7e, 0x79, 0x7c, 0x81, 0x87, 0x82, 0x77, 0x83, 0x7f, 0x79, 0x86, + 0x85, 0x7a, 0x7a, 0x83, 0x83, 0x7e, 0x80, 0x7f, 0x7b, 0x83, 0x83, + 0x7b, 0x7c, 0x80, 0x86, 0x85, 0x78, 0x78, 0x80, 0x87, 0x81, 0x7f, + 0x85, 0x76, 0x78, 0x89, 0x85, 0x80, 0x7d, 0x74, 0x84, 0x8e, 0x79, + 0x7a, 0x80, 0x7f, 0x7d, 0x8c, 0x7f, 0x71, 0x87, 0x7a, 0x80, 0x8a, + 0x7e, 0x7b, 0x77, 0x85, 0x83, 0x7f, 0x7d, 0x7a, 0x8a, 0x81, 0x73, + 0x82, 0x85, 0x80, 0x7d, 0x7e, 0x81, 0x80, 0x81, 0x7d, 0x83, 0x80, + 0x79, 0x86, 0x7e, 0x7a, 0x89, 0x7e, 0x7a, 0x81, 0x7f, 0x7f, 0x81, + 0x86, 0x79, 0x78, 0x86, 0x84, 0x81, 0x7d, 0x75, 0x84, 0x8e, 0x75, + 0x79, 0x82, 0x86, 0x81, 0x79, 0x81, 0x7a, 0x85, 0x85, 0x7b, 0x7d, + 0x7d, 0x86, 0x7f, 0x7c, 0x83, 0x78, 0x7f, 0x8f, 0x7b, 0x6f, 0x84, + 0x8d, 0x7b, 0x79, 0x88, 0x7a, 0x79, 0x84, 0x8c, 0x7a, 0x73, 0x87, + 0x7b, 0x83, 0x8a, 0x7b, 0x75, 0x7c, 0x8c, 0x80, 0x7a, 0x86, 0x7d, + 0x75, 0x84, 0x8d, 0x7c, 0x75, 0x80, 0x85, 0x81, 0x80, 0x81, 0x7b, + 0x7a, 0x87, 0x83, 0x78, 0x81, 0x86, 0x76, 0x80, 0x8a, 0x75, 0x82, + 0x80, 0x7a, 0x8a, 0x80, 0x79, 0x7b, 0x84, 0x83, 0x7b, 0x87, 0x7e, + 0x72, 0x87, 0x86, 0x7f, 0x7b, 0x7e, 0x80, 0x82, 0x84, 0x7a, 0x7e, + 0x85, 0x7f, 0x7b, 0x87, 0x7a, 0x7b, 0x86, 0x7f, 0x83, 0x82, 0x78, + 0x79, 0x89, 0x83, 0x7b, 0x7d, 0x83, 0x83, 0x74, 0x81, 0x8a, 0x7f, + 0x78, 0x7c, 0x85, 0x84, 0x7a, 0x7e, 0x84, 0x7c, 0x82, 0x7a, 0x7c, + 0x8a, 0x86, 0x74, 0x75, 0x8e, 0x83, 0x79, 0x7b, 0x83, 0x84, 0x7e, + 0x7e, 0x7f, 0x78, 0x87, 0x89, 0x74, 0x82, 0x7b, 0x7f, 0x95, 0x77, + 0x69, 0x8d, 0x85, 0x7e, 0x81, 0x72, 0x8a, 0x82, 0x7c, 0x82, 0x76, + 0x85, 0x84, 0x84, 0x74, 0x7f, 0x83, 0x84, 0x82, 0x72, 0x8b, 0x71, + 0x8d, 0x91, 0x61, 0x7f, 0x8e, 0x83, 0x7f, 0x77, 0x7a, 0x87, 0x81, + 0x83, 0x84, 0x6f, 0x79, 0x95, 0x88, 0x67, 0x7b, 0x96, 0x7c, 0x75, + 0x85, 0x7d, 0x81, 0x88, 0x77, 0x7c, 0x89, 0x77, 0x83, 0x8d, 0x6e, + 0x7c, 0x89, 0x7f, 0x84, 0x7d, 0x7e, 0x7b, 0x7b, 0x8a, 0x8a, 0x80, + 0x61, 0x80, 0x9c, 0x7b, 0x7d, 0x78, 0x7f, 0x7f, 0x7c, 0x95, 0x84, + 0x61, 0x75, 0x99, 0x8d, 0x71, 0x73, 0x8a, 0x79, 0x79, 0x9f, 0x7e, + 0x5a, 0x85, 0x9d, 0x7b, 0x72, 0x82, 0x84, 0x7d, 0x77, 0x8a, 0x8f, + 0x69, 0x76, 0x94, 0x79, 0x76, 0x94, 0x82, 0x65, 0x7f, 0x96, 0x82, + 0x74, 0x7a, 0x81, 0x7f, 0x8d, 0x87, 0x6a, 0x74, 0x90, 0x94, 0x76, + 0x6e, 0x7b, 0x8a, 0x90, 0x7c, 0x6b, 0x7d, 0x92, 0x87, 0x6d, 0x7d, + 0x8f, 0x7a, 0x7b, 0x83, 0x7d, 0x7c, 0x8a, 0x7c, 0x78, 0x84, 0x7e, + 0x80, 0x85, 0x7d, 0x74, 0x84, 0x94, 0x78, 0x65, 0x84, 0x98, 0x85, + 0x67, 0x7a, 0x8f, 0x7f, 0x81, 0x83, 0x74, 0x75, 0x91, 0x8d, 0x72, + 0x80, 0x7b, 0x78, 0x91, 0x83, 0x76, 0x7f, 0x79, 0x85, 0x87, 0x80, + 0x76, 0x73, 0x8a, 0x88, 0x86, 0x76, 0x75, 0x82, 0x83, 0x88, 0x81, + 0x78, 0x7a, 0x84, 0x83, 0x7d, 0x7d, 0x82, 0x85, 0x7d, 0x76, 0x82, + 0x85, 0x81, 0x80, 0x7a, 0x81, 0x7f, 0x82, 0x85, 0x7d, 0x78, 0x83, + 0x85, 0x7a, 0x7f, 0x83, 0x7e, 0x81, 0x83, 0x7b, 0x7e, 0x86, 0x84, + 0x75, 0x7b, 0x88, 0x82, 0x7b, 0x78, 0x85, 0x85, 0x7d, 0x7d, 0x7f, + 0x83, 0x7f, 0x7d, 0x7d, 0x84, 0x7c, 0x82, 0x84, 0x77, 0x7f, 0x81, + 0x86, 0x7b, 0x7b, 0x85, 0x7d, 0x82, 0x83, 0x7b, 0x7d, 0x7f, 0x89, + 0x7e, 0x7a, 0x83, 0x7f, 0x7d, 0x80, 0x84, 0x7c, 0x7d, 0x83, 0x80, + 0x7a, 0x80, 0x82, 0x81, 0x89, 0x77, 0x73, 0x89, 0x88, 0x7c, 0x7c, + 0x7d, 0x7e, 0x83, 0x82, 0x81, 0x7a, 0x7d, 0x8a, 0x81, 0x73, 0x81, + 0x8b, 0x7d, 0x79, 0x7f, 0x84, 0x7d, 0x7e, 0x86, 0x79, 0x7a, 0x87, + 0x86, 0x7b, 0x79, 0x84, 0x81, 0x7c, 0x87, 0x81, 0x73, 0x81, 0x89, + 0x7a, 0x7c, 0x87, 0x7c, 0x7a, 0x85, 0x82, 0x79, 0x82, 0x86, 0x77, + 0x7f, 0x87, 0x7c, 0x7e, 0x7f, 0x80, 0x7f, 0x7d, 0x85, 0x80, 0x7b, + 0x7d, 0x7f, 0x85, 0x80, 0x7e, 0x81, 0x7d, 0x82, 0x7f, 0x80, 0x81, + 0x79, 0x81, 0x85, 0x81, 0x7c, 0x7a, 0x86, 0x84, 0x77, 0x82, 0x82, + 0x79, 0x84, 0x84, 0x7d, 0x7c, 0x85, 0x81, 0x75, 0x83, 0x8a, 0x7c, + 0x7a, 0x82, 0x7e, 0x7e, 0x84, 0x7f, 0x7b, 0x81, 0x84, 0x7c, 0x7b, + 0x83, 0x84, 0x7e, 0x7a, 0x80, 0x83, 0x82, 0x7d, 0x7d, 0x81, 0x82, + 0x80, 0x7c, 0x81, 0x83, 0x80, 0x81, 0x82, 0x7d, 0x81, 0x89, 0x80, + 0x7b, 0x83, 0x85, 0x7c, 0x7d, 0x81, 0x7f, 0x7f, 0x7d, 0x7c, 0x7d, + 0x7d, 0x7c, 0x72, 0x6d, 0x76, 0x7a, 0x75, 0x73, 0x7a, 0x85, 0x86, + 0x84, 0x89, 0x8e, 0x8f, 0x8c, 0x88, 0x85, 0x84, 0x82, 0x7f, 0x7b, + 0x79, 0x7d, 0x81, 0x7e, 0x7f, 0x86, 0x89, 0x88, 0x86, 0x88, 0x8d, + 0x8b, 0x85, 0x80, 0x80, 0x85, 0x80, 0x7b, 0x7d, 0x81, 0x84, 0x82, + 0x73, 0x42, 0x46, 0x89, 0x71, 0x39, 0x52, 0x82, 0x92, 0x77, 0x75, + 0xa1, 0xad, 0xa1, 0xa1, 0x9a, 0x91, 0x97, 0x96, 0x7a, 0x64, 0x71, + 0x82, 0x72, 0x59, 0x6a, 0x8c, 0x89, 0x7c, 0x82, 0x93, 0x99, 0x8c, + 0x85, 0x82, 0x7b, 0x7b, 0x75, 0x68, 0x6a, 0x7a, 0x7f, 0x77, 0x7d, + 0x92, 0x98, 0x8d, 0x8f, 0x99, 0x96, 0x8c, 0x87, 0x88, 0x86, 0x83, + 0x82, 0x7a, 0x61, 0x32, 0x48, 0x81, 0x4d, 0x2e, 0x61, 0x89, 0x91, + 0x76, 0x8e, 0xbe, 0xb2, 0xac, 0xa9, 0x96, 0x98, 0x92, 0x7c, 0x5e, + 0x57, 0x73, 0x6f, 0x53, 0x5e, 0x82, 0x96, 0x88, 0x89, 0xa1, 0xa8, + 0x9f, 0x91, 0x8a, 0x86, 0x7a, 0x6a, 0x56, 0x53, 0x63, 0x65, 0x63, + 0x75, 0x92, 0x9b, 0x95, 0x9c, 0xa9, 0xa4, 0x95, 0x8d, 0x8c, 0x87, + 0x7d, 0x76, 0x73, 0x77, 0x7c, 0x76, 0x6f, 0x44, 0x43, 0x8b, 0x69, + 0x39, 0x64, 0x8b, 0x96, 0x76, 0x80, 0xb6, 0xaa, 0x9d, 0x9e, 0x8b, + 0x95, 0x92, 0x74, 0x65, 0x62, 0x7e, 0x78, 0x55, 0x70, 0x8e, 0x92, + 0x88, 0x84, 0x9e, 0xa2, 0x8f, 0x86, 0x81, 0x85, 0x7c, 0x68, 0x61, + 0x64, 0x6e, 0x65, 0x5f, 0x77, 0x8b, 0x8c, 0x8b, 0x9b, 0xa5, 0x9d, + 0x91, 0x8f, 0x91, 0x8a, 0x7e, 0x78, 0x7c, 0x82, 0x7d, 0x79, 0x80, + 0x84, 0x7d, 0x48, 0x47, 0x89, 0x60, 0x3b, 0x61, 0x7e, 0x8c, 0x74, + 0x82, 0xb1, 0xa9, 0xa1, 0xa1, 0x8f, 0x9c, 0x97, 0x6e, 0x66, 0x6d, + 0x7b, 0x69, 0x53, 0x78, 0x8c, 0x85, 0x83, 0x8b, 0xa5, 0xa1, 0x8b, + 0x8a, 0x8c, 0x8c, 0x79, 0x61, 0x68, 0x73, 0x68, 0x5a, 0x63, 0x79, + 0x82, 0x7d, 0x84, 0x9b, 0xa1, 0x95, 0x90, 0x98, 0x95, 0x85, 0x80, + 0x82, 0x81, 0x7b, 0x7b, 0x83, 0x85, 0x85, 0x84, 0x83, 0x75, 0x44, + 0x62, 0x7e, 0x42, 0x4d, 0x6d, 0x73, 0x7f, 0x79, 0x8f, 0xb0, 0xa4, + 0x9e, 0xa2, 0x9c, 0xa0, 0x84, 0x74, 0x77, 0x70, 0x71, 0x5c, 0x64, + 0x80, 0x78, 0x7c, 0x88, 0x94, 0x9f, 0x92, 0x8e, 0x97, 0x92, 0x83, + 0x73, 0x71, 0x76, 0x67, 0x61, 0x64, 0x6a, 0x79, 0x73, 0x74, 0x8e, + 0x98, 0x8e, 0x91, 0x9d, 0x98, 0x8e, 0x87, 0x86, 0x84, 0x80, 0x79, + 0x7c, 0x81, 0x80, 0x83, 0x84, 0x8b, 0x85, 0x87, 0x61, 0x4a, 0x88, + 0x5e, 0x37, 0x70, 0x67, 0x6a, 0x80, 0x75, 0x95, 0xaa, 0x9c, 0x9f, + 0xa2, 0xb1, 0x96, 0x7e, 0x90, 0x78, 0x75, 0x6a, 0x58, 0x74, 0x6f, + 0x66, 0x79, 0x83, 0x8e, 0x8d, 0x8e, 0x9c, 0x97, 0x93, 0x86, 0x81, + 0x87, 0x71, 0x6c, 0x6d, 0x6c, 0x6b, 0x68, 0x72, 0x77, 0x7e, 0x83, + 0x8c, 0x93, 0x91, 0x94, 0x95, 0x90, 0x88, 0x88, 0x85, 0x7f, 0x7a, + 0x7b, 0x7e, 0x7d, 0x80, 0x85, 0x89, 0x8d, 0x88, 0x8e, 0x62, 0x58, + 0x95, 0x49, 0x46, 0x79, 0x4b, 0x72, 0x71, 0x61, 0xa0, 0x95, 0x92, + 0xa3, 0xa9, 0xb4, 0x93, 0x9d, 0x96, 0x84, 0x88, 0x63, 0x72, 0x75, + 0x58, 0x6a, 0x6c, 0x74, 0x7a, 0x79, 0x8e, 0x90, 0x98, 0x91, 0x95, + 0x9f, 0x87, 0x85, 0x7c, 0x7a, 0x74, 0x63, 0x6a, 0x6c, 0x67, 0x6e, + 0x7d, 0x81, 0x86, 0x8e, 0x97, 0x96, 0x91, 0x93, 0x93, 0x89, 0x81, + 0x82, 0x7e, 0x77, 0x75, 0x7b, 0x7b, 0x7f, 0x80, 0x89, 0x8a, 0x96, + 0x83, 0x48, 0x92, 0x73, 0x3a, 0x78, 0x59, 0x65, 0x69, 0x61, 0x84, + 0x8c, 0x7f, 0x95, 0xae, 0x96, 0xa0, 0xa1, 0x9e, 0x99, 0x86, 0x88, + 0x86, 0x77, 0x6d, 0x73, 0x71, 0x6f, 0x6f, 0x78, 0x77, 0x76, 0x82, + 0x86, 0x85, 0x86, 0x8d, 0x8d, 0x89, 0x84, 0x86, 0x84, 0x7d, 0x7a, + 0x7b, 0x79, 0x77, 0x7a, 0x7c, 0x7e, 0x7e, 0x84, 0x85, 0x84, 0x85, + 0x87, 0x86, 0x82, 0x82, 0x82, 0x7f, 0x7e, 0x7e, 0x7c, 0x7d, 0x7d, + 0x80, 0x81, 0x80, 0x88, 0x88, 0x8d, 0x7f, 0x74, 0x83, 0x6d, 0x66, + 0x6e, 0x67, 0x67, 0x65, 0x6a, 0x74, 0x73, 0x7c, 0x8a, 0x8a, 0x90, + 0x97, 0x9b, 0x9a, 0x95, 0x98, 0x95, 0x8a, 0x88, 0x84, 0x7f, 0x7a, + 0x75, 0x78, 0x78, 0x74, 0x78, 0x7e, 0x7f, 0x81, 0x86, 0x86, 0x86, + 0x85, 0x85, 0x82, 0x7e, 0x7e, 0x7a, 0x76, 0x76, 0x76, 0x76, 0x77, + 0x79, 0x7e, 0x7f, 0x81, 0x85, 0x86, 0x87, 0x88, 0x88, 0x88, 0x83, + 0x83, 0x82, 0x7d, 0x7b, 0x7c, 0x7b, 0x7a, 0x7a, 0x7d, 0x7e, 0x7e, + 0x82, 0x7e, 0x82, 0x82, 0x7f, 0x82, 0x7a, 0x7e, 0x7a, 0x73, 0x77, + 0x77, 0x74, 0x74, 0x77, 0x7a, 0x7b, 0x7b, 0x81, 0x83, 0x84, 0x89, + 0x8b, 0x8a, 0x8c, 0x8c, 0x8c, 0x89, 0x86, 0x87, 0x84, 0x81, 0x7f, + 0x7d, 0x7d, 0x7d, 0x7b, 0x7a, 0x7d, 0x7f, 0x7f, 0x7e, 0x80, 0x82, + 0x81, 0x80, 0x81, 0x82, 0x7f, 0x80, 0x7e, 0x7c, 0x81, 0x7d, 0x7c, + 0x80, 0x7d, 0x7e, 0x81, 0x7c, 0x80, 0x83, 0x7f, 0x7f, 0x7f, 0x7f, + 0x80, 0x7d, 0x7c, 0x7c, 0x7c, 0x7d, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, + 0x7f, 0x7f, 0x82, 0x81, 0x7f, 0x81, 0x7f, 0x7e, 0x81, 0x7f, 0x7f, + 0x80, 0x7f, 0x82, 0x80, 0x7d, 0x81, 0x80, 0x7e, 0x7d, 0x7d, 0x80, + 0x7e, 0x7d, 0x80, 0x7e, 0x80, 0x81, 0x7f, 0x80, 0x81, 0x82, 0x83, + 0x80, 0x82, 0x83, 0x81, 0x83, 0x81, 0x82, 0x82, 0x81, 0x80, 0x80, + 0x7f, 0x80, 0x80, 0x80, 0x7e, 0x7e, 0x82, 0x7e, 0x7b, 0x7f, 0x7e, + 0x7d, 0x7e, 0x7c, 0x80, 0x80, 0x7f, 0x81, 0x80, 0x83, 0x82, 0x80, + 0x81, 0x81, 0x7f, 0x80, 0x7f, 0x7c, 0x81, 0x7b, 0x7b, 0x7f, 0x7a, + 0x7f, 0x7c, 0x7c, 0x83, 0x7b, 0x81, 0x83, 0x7d, 0x82, 0x81, 0x7e, + 0x81, 0x7c, 0x81, 0x7d, 0x7b, 0x82, 0x7b, 0x80, 0x7f, 0x81, 0x83, + 0x81, 0x84, 0x82, 0x81, 0x82, 0x7f, 0x7f, 0x81, 0x7a, 0x7c, 0x7e, + 0x7a, 0x7e, 0x7d, 0x80, 0x81, 0x7e, 0x85, 0x83, 0x80, 0x84, 0x82, + 0x81, 0x83, 0x7b, 0x81, 0x7c, 0x7a, 0x80, 0x7a, 0x80, 0x7f, 0x7c, + 0x85, 0x80, 0x81, 0x86, 0x7d, 0x84, 0x82, 0x7a, 0x82, 0x79, 0x7c, + 0x80, 0x77, 0x81, 0x7d, 0x7e, 0x84, 0x7f, 0x84, 0x83, 0x80, 0x86, + 0x7c, 0x80, 0x82, 0x78, 0x82, 0x7a, 0x7b, 0x80, 0x7b, 0x7e, 0x82, + 0x7d, 0x84, 0x81, 0x80, 0x87, 0x7e, 0x83, 0x84, 0x7c, 0x81, 0x81, + 0x7c, 0x80, 0x7d, 0x7b, 0x7f, 0x7d, 0x7c, 0x7e, 0x80, 0x80, 0x80, + 0x81, 0x81, 0x7f, 0x82, 0x81, 0x7f, 0x80, 0x81, 0x80, 0x7e, 0x7f, + 0x80, 0x7f, 0x7f, 0x7f, 0x7e, 0x81, 0x7e, 0x80, 0x7e, 0x7e, 0x81, + 0x7d, 0x80, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7e, 0x80, 0x81, + 0x7f, 0x81, 0x80, 0x7e, 0x83, 0x7f, 0x7d, 0x81, 0x7e, 0x7d, 0x7f, + 0x7e, 0x81, 0x7f, 0x82, 0x80, 0x80, 0x84, 0x7c, 0x82, 0x82, 0x7c, + 0x81, 0x7e, 0x7e, 0x7f, 0x7d, 0x7e, 0x7f, 0x7e, 0x81, 0x7e, 0x80, + 0x82, 0x80, 0x80, 0x82, 0x7f, 0x80, 0x82, 0x7f, 0x7f, 0x81, 0x7f, + 0x80, 0x7f, 0x7f, 0x80, 0x7e, 0x81, 0x7f, 0x7d, 0x81, 0x7e, 0x7e, + 0x81, 0x7d, 0x81, 0x7f, 0x7f, 0x7f, 0x81, 0x7e, 0x81, 0x7f, 0x7f, + 0x81, 0x7a, 0x83, 0x7f, 0x7d, 0x81, 0x81, 0x80, 0x80, 0x82, 0x80, + 0x82, 0x7e, 0x81, 0x7f, 0x7e, 0x7f, 0x7c, 0x7f, 0x7d, 0x7e, 0x7e, + 0x7f, 0x80, 0x80, 0x83, 0x83, 0x81, 0x84, 0x83, 0x80, 0x7f, 0x7f, + 0x7e, 0x7d, 0x7d, 0x7b, 0x7e, 0x7c, 0x7f, 0x7f, 0x7f, 0x83, 0x82, + 0x81, 0x84, 0x81, 0x81, 0x81, 0x7f, 0x81, 0x7f, 0x7e, 0x80, 0x7d, + 0x7f, 0x81, 0x7e, 0x7f, 0x81, 0x7f, 0x7e, 0x7e, 0x7d, 0x7e, 0x7e, + 0x7d, 0x7e, 0x7f, 0x80, 0x82, 0x81, 0x81, 0x83, 0x82, 0x84, 0x80, + 0x80, 0x82, 0x7d, 0x7e, 0x7d, 0x7d, 0x7c, 0x7e, 0x7f, 0x7f, 0x7f, + 0x81, 0x80, 0x83, 0x82, 0x80, 0x80, 0x80, 0x80, 0x7e, 0x7f, 0x7f, + 0x80, 0x7d, 0x7e, 0x7f, 0x7e, 0x81, 0x7e, 0x7f, 0x81, 0x80, 0x7f, + 0x81, 0x80, 0x80, 0x81, 0x7e, 0x81, 0x7f, 0x80, 0x81, 0x7f, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7e, 0x7f, 0x7e, 0x7f, 0x7d, 0x7f, + 0x7f, 0x7e, 0x80, 0x7f, 0x80, 0x81, 0x80, 0x7f, 0x82, 0x81, 0x80, + 0x80, 0x80, 0x81, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x7e, 0x7f, 0x7e, + 0x80, 0x7f, 0x80, 0x80, 0x80, 0x81, 0x7f, 0x80, 0x80, 0x7e, 0x7d, + 0x7e, 0x7e, 0x7e, 0x7f, 0x7e, 0x81, 0x81, 0x81, 0x82, 0x80, 0x81, + 0x81, 0x7e, 0x7f, 0x7f, 0x7d, 0x7f, 0x7e, 0x7f, 0x81, 0x7f, 0x82, + 0x82, 0x82, 0x82, 0x81, 0x80, 0x81, 0x7f, 0x7e, 0x7d, 0x7c, 0x7d, + 0x7c, 0x7c, 0x7e, 0x7f, 0x7e, 0x81, 0x82, 0x82, 0x82, 0x82, 0x81, + 0x81, 0x80, 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x80, 0x81, + 0x80, 0x81, 0x82, 0x80, 0x81, 0x80, 0x7e, 0x7f, 0x7f, 0x7e, 0x7c, + 0x7d, 0x7f, 0x7e, 0x7f, 0x7f, 0x81, 0x81, 0x81, 0x82, 0x82, 0x82, + 0x81, 0x80, 0x80, 0x7f, 0x7e, 0x7e, 0x7d, 0x7e, 0x7e, 0x7e, 0x7f, + 0x7f, 0x80, 0x81, 0x81, 0x82, 0x81, 0x81, 0x81, 0x80, 0x7f, 0x7f, + 0x7e, 0x7e, 0x7e, 0x7d, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x81, 0x81, + 0x81, 0x81, 0x80, 0x80, 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, 0x7f, 0x7e, + 0x7f, 0x7f, 0x81, 0x81, 0x80, 0x80, 0x81, 0x81, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7e, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x81, 0x81, + 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x80, + 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x81, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x81, 0x80, 0x7f, 0x7f, + 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, + 0x80, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x7e, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x81, 0x81, + 0x81, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7e, 0x7f, 0x7e, 0x7e, 0x7e, + 0x7f, 0x80, 0x80, 0x80, 0x81, 0x81, 0x81, 0x81, 0x80, 0x80, 0x7f, + 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, + 0x81, 0x81, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7e, 0x7f, 0x7f, 0x7f, + 0x7e, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, + 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x80, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x7f, + 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x80, + 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x80, + 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x80, + 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, + 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, + 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, + 0x7e, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, + 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x80, + 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x80, + 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x7f, + 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x7f, + 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x81, 0x7f, 0x80, 0x80, + 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, + 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x81, 0x7d, 0x81, 0x80, + 0x7f, 0x80, 0x7f, 0x7e, 0x81, 0x7e, 0x7f, 0x81, 0x7e, 0x81, 0x80, + 0x7e, 0x81, 0x7f, 0x7e, 0x82, 0x7e, 0x80, 0x81, 0x7d, 0x81, 0x80, + 0x7d, 0x81, 0x7f, 0x7e, 0x83, 0x7d, 0x80, 0x81, 0x7c, 0x81, 0x81, + 0x7d, 0x81, 0x80, 0x7d, 0x82, 0x7e, 0x7f, 0x82, 0x7e, 0x81, 0x81, + 0x7e, 0x81, 0x80, 0x7e, 0x82, 0x7e, 0x7f, 0x80, 0x7e, 0x7f, 0x80, + 0x7e, 0x80, 0x80, 0x7e, 0x81, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x81, + 0x7e, 0x80, 0x80, 0x7f, 0x81, 0x7e, 0x7f, 0x80, 0x7f, 0x80, 0x7f, + 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7e, 0x82, 0x7e, + 0x80, 0x81, 0x7d, 0x81, 0x80, 0x7f, 0x81, 0x7f, 0x7e, 0x82, 0x7e, + 0x80, 0x80, 0x7e, 0x80, 0x7f, 0x7e, 0x81, 0x7f, 0x7f, 0x81, 0x7e, + 0x81, 0x7f, 0x7f, 0x80, 0x80, 0x7e, 0x81, 0x7e, 0x80, 0x81, 0x7e, + 0x81, 0x7f, 0x7f, 0x80, 0x80, 0x7e, 0x82, 0x7d, 0x80, 0x80, 0x7f, + 0x80, 0x80, 0x7f, 0x7f, 0x82, 0x7c, 0x82, 0x7d, 0x80, 0x80, 0x7e, + 0x80, 0x7f, 0x80, 0x7f, 0x81, 0x7e, 0x82, 0x7e, 0x81, 0x7f, 0x7f, + 0x7f, 0x81, 0x7f, 0x7f, 0x81, 0x7d, 0x82, 0x7e, 0x80, 0x7f, 0x80, + 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7e, 0x80, 0x7f, 0x80, 0x7f, 0x81, + 0x7f, 0x7f, 0x81, 0x7e, 0x81, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x81, + 0x7f, 0x80, 0x80, 0x7e, 0x80, 0x80, 0x7e, 0x7f, 0x80, 0x7e, 0x81, + 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x7e, 0x81, + 0x7f, 0x7f, 0x80, 0x7e, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, + 0x7f, 0x80, 0x7e, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7e, 0x80, 0x7f, + 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x81, 0x80, + 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7e, 0x80, 0x80, 0x7e, 0x80, 0x7f, + 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x7e, 0x80, 0x7f, + 0x7f, 0x81, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x7e, 0x80, 0x7f, + 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x80, + 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, + 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7f, + 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, + 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x80, + 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, + 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x80, + 0x7e, 0x80, 0x80, 0x7e, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x80, + 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x80, + 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x7f, + 0x80, 0x7f, 0x80, + }, + { // 7 + 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7e, 0x80, 0x7f, 0x7f, + 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x7f, + 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, + 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7e, 0x80, 0x7f, 0x7f, + 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, + 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x80, + 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, + 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, + 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, + 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x80, + 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x80, + 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, + 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x81, 0x7e, 0x81, 0x7f, 0x7f, + 0x80, 0x7e, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7f, + 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x7f, + 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7e, 0x80, + 0x7f, 0x7f, 0x81, 0x7e, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x80, + 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, + 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, + 0x80, 0x7f, 0x7f, 0x81, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, + 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x80, + 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x80, + 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x80, + 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x7e, 0x81, 0x7f, 0x7f, + 0x81, 0x7e, 0x80, 0x80, 0x7e, 0x81, 0x7f, 0x7f, 0x82, 0x7d, 0x80, + 0x81, 0x7d, 0x82, 0x7e, 0x7f, 0x81, 0x7e, 0x80, 0x7f, 0x7f, 0x80, + 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7e, 0x80, + 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, + 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x80, + 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, + 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x80, + 0x7f, 0x80, 0x80, 0x7e, 0x81, 0x7e, 0x80, 0x80, 0x7e, 0x81, 0x7e, + 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x7e, + 0x81, 0x7f, 0x7f, 0x81, 0x7e, 0x81, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, + 0x80, 0x7f, 0x7f, 0x81, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x80, + 0x7e, 0x81, 0x7f, 0x7f, 0x81, 0x7f, 0x7f, 0x80, 0x7e, 0x80, 0x80, + 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7e, 0x81, 0x7f, 0x7f, 0x81, 0x7f, + 0x7f, 0x81, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, + 0x81, 0x7e, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, + 0x80, 0x7e, 0x81, 0x7f, 0x7f, 0x81, 0x7e, 0x80, 0x80, 0x7e, 0x81, + 0x80, 0x7e, 0x82, 0x7e, 0x80, 0x80, 0x7e, 0x81, 0x7f, 0x7f, 0x81, + 0x7e, 0x80, 0x81, 0x7e, 0x81, 0x7f, 0x7e, 0x81, 0x7e, 0x81, 0x7f, + 0x7e, 0x81, 0x7e, 0x7f, 0x81, 0x7e, 0x80, 0x80, 0x7e, 0x81, 0x7f, + 0x7f, 0x81, 0x7e, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7f, + 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x80, + 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, + 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x81, 0x7e, 0x80, 0x7f, + 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x7e, 0x80, 0x80, 0x7e, + 0x81, 0x7e, 0x81, 0x7f, 0x7f, 0x81, 0x7f, 0x80, 0x80, 0x7f, 0x80, + 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, + 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x80, + 0x7f, 0x7f, 0x80, 0x7e, 0x80, 0x80, 0x7e, 0x81, 0x7f, 0x80, 0x80, + 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x81, + 0x7e, 0x80, 0x80, 0x7e, 0x81, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, + 0x80, 0x7e, 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x7e, 0x81, 0x7f, 0x7f, + 0x81, 0x7e, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x81, 0x7e, 0x80, + 0x80, 0x7f, 0x81, 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, + 0x7f, 0x7f, 0x81, 0x7e, 0x81, 0x7f, 0x7f, 0x81, 0x7f, 0x7f, 0x80, + 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, + 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, + 0x7f, 0x80, 0x80, 0x7e, 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x81, + 0x7f, 0x7f, 0x81, 0x7e, 0x81, 0x7f, 0x7e, 0x82, 0x7e, 0x80, 0x80, + 0x7e, 0x81, 0x7e, 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x7e, 0x81, 0x7f, + 0x7f, 0x81, 0x7e, 0x81, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, + 0x7f, 0x80, 0x7e, 0x81, 0x7e, 0x80, 0x81, 0x7d, 0x82, 0x7f, 0x7f, + 0x81, 0x7e, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7e, 0x81, 0x7e, + 0x80, 0x7f, 0x80, 0x7f, 0x81, 0x7e, 0x80, 0x80, 0x7f, 0x80, 0x7f, + 0x80, 0x7f, 0x81, 0x7f, 0x80, 0x80, 0x80, 0x7e, 0x80, 0x80, 0x7e, + 0x81, 0x7f, 0x7d, 0x83, 0x7e, 0x7f, 0x82, 0x7c, 0x81, 0x7f, 0x7f, + 0x81, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x82, 0x7c, 0x81, 0x80, 0x7e, + 0x82, 0x7e, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, + 0x81, 0x7e, 0x80, 0x81, 0x7e, 0x81, 0x80, 0x7e, 0x81, 0x7d, 0x80, + 0x81, 0x7d, 0x82, 0x7e, 0x7f, 0x82, 0x7d, 0x80, 0x80, 0x7e, 0x81, + 0x7f, 0x7e, 0x83, 0x7c, 0x80, 0x81, 0x7e, 0x81, 0x7f, 0x80, 0x7f, + 0x7f, 0x81, 0x7f, 0x7f, 0x81, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7f, + 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x80, + 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x81, 0x7d, 0x81, 0x80, 0x7f, + 0x80, 0x7e, 0x81, 0x7f, 0x7f, 0x80, 0x7e, 0x80, 0x80, 0x7e, 0x82, + 0x7e, 0x7e, 0x82, 0x7e, 0x80, 0x80, 0x7e, 0x80, 0x7f, 0x7f, 0x81, + 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x7e, 0x80, 0x80, 0x7f, 0x81, + 0x7e, 0x81, 0x7e, 0x7f, 0x82, 0x7e, 0x7f, 0x81, 0x7e, 0x7f, 0x81, + 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, + 0x7f, 0x81, 0x7e, 0x7f, 0x81, 0x7e, 0x80, 0x7f, 0x80, 0x80, 0x7e, + 0x81, 0x7f, 0x7e, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x81, 0x7f, + 0x80, 0x7f, 0x7f, 0x81, 0x7d, 0x81, 0x80, 0x7e, 0x80, 0x7f, 0x7f, + 0x80, 0x7e, 0x81, 0x7e, 0x7f, 0x82, 0x7d, 0x81, 0x80, 0x7d, 0x82, + 0x7e, 0x7f, 0x82, 0x7c, 0x81, 0x80, 0x7d, 0x83, 0x7d, 0x80, 0x82, + 0x7d, 0x82, 0x7f, 0x7e, 0x82, 0x7e, 0x7f, 0x80, 0x7e, 0x80, 0x7f, + 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x7e, 0x81, 0x7e, + 0x7f, 0x81, 0x7e, 0x81, 0x7f, 0x7e, 0x81, 0x7f, 0x7f, 0x81, 0x7e, + 0x80, 0x80, 0x7e, 0x80, 0x80, 0x7e, 0x81, 0x7f, 0x7f, 0x81, 0x7e, + 0x80, 0x7f, 0x7f, 0x80, 0x7e, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, + 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x81, 0x7f, 0x80, 0x80, 0x7e, 0x81, + 0x80, 0x7e, 0x81, 0x7e, 0x7f, 0x80, 0x7e, 0x80, 0x7f, 0x7f, 0x81, + 0x7e, 0x80, 0x81, 0x7e, 0x80, 0x80, 0x7e, 0x80, 0x80, 0x7f, 0x81, + 0x7e, 0x81, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x80, + 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x7e, 0x81, 0x7e, + 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x81, 0x7e, + 0x7f, 0x81, 0x7e, 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, + 0x7f, 0x80, 0x7e, 0x80, 0x80, 0x7f, 0x81, 0x7f, 0x80, 0x81, 0x7e, + 0x80, 0x80, 0x7e, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7e, + 0x80, 0x80, 0x7d, 0x82, 0x7f, 0x7e, 0x82, 0x7f, 0x7f, 0x81, 0x7e, + 0x80, 0x80, 0x7d, 0x82, 0x7e, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, + 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x81, 0x7e, 0x80, 0x80, 0x7d, 0x81, + 0x80, 0x7e, 0x82, 0x7e, 0x80, 0x80, 0x7e, 0x81, 0x80, 0x7d, 0x81, + 0x7f, 0x7e, 0x81, 0x7e, 0x80, 0x80, 0x7e, 0x80, 0x80, 0x7e, 0x80, + 0x81, 0x7e, 0x81, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, + 0x80, 0x7e, 0x80, 0x7f, 0x7f, 0x81, 0x7e, 0x80, 0x80, 0x7e, 0x81, + 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x7f, + 0x7f, 0x81, 0x7e, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7e, 0x80, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, 0x7f, 0x7f, 0x7e, 0x7f, 0x7e, 0x7e, + 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x81, 0x81, 0x82, 0x81, 0x82, 0x84, + 0x82, 0x83, 0x83, 0x81, 0x83, 0x81, 0x81, 0x83, 0x7f, 0x81, 0x81, + 0x7d, 0x81, 0x7f, 0x7d, 0x82, 0x7d, 0x82, 0x79, 0x72, 0x87, 0x70, + 0x74, 0x7e, 0x6d, 0x80, 0x72, 0x74, 0x87, 0x77, 0x81, 0x84, 0x84, + 0x8b, 0x86, 0x89, 0x8d, 0x8c, 0x83, 0x8a, 0x87, 0x82, 0x84, 0x7a, + 0x83, 0x7f, 0x75, 0x7f, 0x7a, 0x7b, 0x7c, 0x7a, 0x80, 0x7f, 0x7c, + 0x7f, 0x83, 0x7f, 0x81, 0x81, 0x81, 0x83, 0x7a, 0x7f, 0x81, 0x7a, + 0x7c, 0x7d, 0x7d, 0x7d, 0x7b, 0x81, 0x83, 0x7f, 0x84, 0x87, 0x86, + 0x86, 0x86, 0x8a, 0x87, 0x84, 0x89, 0x84, 0x85, 0x82, 0x87, 0x76, + 0x65, 0x8f, 0x61, 0x66, 0x7d, 0x58, 0x82, 0x64, 0x69, 0x8e, 0x6f, + 0x84, 0x8a, 0x8b, 0x95, 0x8f, 0x90, 0x99, 0x96, 0x83, 0x92, 0x88, + 0x7d, 0x82, 0x70, 0x7f, 0x75, 0x69, 0x79, 0x73, 0x74, 0x78, 0x7b, + 0x81, 0x85, 0x7f, 0x89, 0x90, 0x80, 0x8b, 0x89, 0x80, 0x84, 0x78, + 0x7b, 0x7c, 0x70, 0x79, 0x7c, 0x77, 0x80, 0x81, 0x86, 0x8a, 0x86, + 0x8f, 0x90, 0x87, 0x90, 0x88, 0x8b, 0x86, 0x8a, 0x80, 0x47, 0x96, + 0x62, 0x3d, 0x8a, 0x43, 0x7a, 0x6b, 0x58, 0xa0, 0x7b, 0x85, 0x9e, + 0xa0, 0x9b, 0x9d, 0x95, 0x96, 0x99, 0x70, 0x83, 0x82, 0x64, 0x72, + 0x68, 0x74, 0x75, 0x6a, 0x81, 0x89, 0x7f, 0x87, 0x94, 0x8c, 0x8e, + 0x85, 0x86, 0x8b, 0x75, 0x72, 0x7d, 0x76, 0x6b, 0x75, 0x7c, 0x79, + 0x77, 0x82, 0x8c, 0x82, 0x84, 0x8f, 0x8c, 0x83, 0x84, 0x89, 0x84, + 0x7c, 0x81, 0x86, 0x82, 0x7e, 0x8d, 0x88, 0x92, 0x62, 0x67, 0xa6, + 0x3c, 0x67, 0x7f, 0x52, 0x81, 0x57, 0x7f, 0x94, 0x76, 0x89, 0xa1, + 0x9b, 0x8b, 0x99, 0x8f, 0x92, 0x82, 0x74, 0x8b, 0x77, 0x6a, 0x7a, + 0x7b, 0x7a, 0x77, 0x7e, 0x89, 0x82, 0x7d, 0x89, 0x8a, 0x7d, 0x7f, + 0x81, 0x80, 0x7b, 0x73, 0x81, 0x84, 0x72, 0x80, 0x87, 0x7e, 0x81, + 0x81, 0x82, 0x7f, 0x77, 0x7f, 0x80, 0x78, 0x7e, 0x85, 0x83, 0x82, + 0x88, 0x89, 0x89, 0x84, 0x88, 0x89, 0x82, 0x88, 0x84, 0x93, 0x4d, + 0x70, 0x9a, 0x2c, 0x7e, 0x73, 0x5d, 0x88, 0x62, 0x8f, 0x90, 0x82, + 0x8d, 0xa1, 0x8d, 0x85, 0x94, 0x80, 0x87, 0x7b, 0x77, 0x85, 0x76, + 0x76, 0x84, 0x81, 0x7e, 0x82, 0x84, 0x83, 0x7c, 0x7c, 0x85, 0x7b, + 0x79, 0x80, 0x7e, 0x7e, 0x7d, 0x80, 0x87, 0x80, 0x7f, 0x87, 0x82, + 0x7d, 0x80, 0x7d, 0x79, 0x7a, 0x75, 0x7b, 0x7d, 0x7a, 0x83, 0x86, + 0x84, 0x88, 0x8a, 0x87, 0x87, 0x85, 0x85, 0x81, 0x83, 0x7f, 0x87, + 0x80, 0x8b, 0x7b, 0x4b, 0x9e, 0x61, 0x4b, 0x91, 0x5e, 0x77, 0x76, + 0x79, 0x8c, 0x88, 0x81, 0x95, 0x95, 0x7f, 0x93, 0x86, 0x83, 0x84, + 0x7d, 0x80, 0x81, 0x79, 0x7f, 0x84, 0x7c, 0x82, 0x81, 0x80, 0x7f, + 0x7c, 0x7f, 0x7f, 0x7a, 0x7e, 0x81, 0x7e, 0x7a, 0x83, 0x85, 0x7c, + 0x85, 0x83, 0x81, 0x80, 0x7d, 0x7e, 0x7a, 0x78, 0x7a, 0x7c, 0x7a, + 0x80, 0x82, 0x84, 0x86, 0x87, 0x88, 0x86, 0x86, 0x85, 0x84, 0x81, + 0x82, 0x82, 0x7f, 0x87, 0x81, 0x91, 0x63, 0x65, 0x9a, 0x49, 0x6a, + 0x81, 0x63, 0x77, 0x74, 0x7f, 0x87, 0x86, 0x80, 0x9b, 0x8a, 0x84, + 0x92, 0x86, 0x86, 0x84, 0x83, 0x81, 0x84, 0x7b, 0x81, 0x83, 0x7b, + 0x7f, 0x80, 0x7c, 0x7a, 0x7c, 0x7c, 0x7d, 0x78, 0x83, 0x7f, 0x7e, + 0x88, 0x83, 0x84, 0x86, 0x83, 0x80, 0x81, 0x7b, 0x7b, 0x7b, 0x75, + 0x78, 0x7a, 0x7a, 0x7e, 0x82, 0x83, 0x87, 0x86, 0x85, 0x88, 0x84, + 0x84, 0x85, 0x81, 0x82, 0x81, 0x82, 0x80, 0x87, 0x82, 0x91, 0x6f, + 0x5a, 0x99, 0x4e, 0x5c, 0x8b, 0x5a, 0x76, 0x7a, 0x7c, 0x84, 0x8c, + 0x83, 0x95, 0x94, 0x81, 0x94, 0x8a, 0x82, 0x85, 0x85, 0x7f, 0x81, + 0x7e, 0x7d, 0x83, 0x7b, 0x7c, 0x81, 0x7c, 0x77, 0x7e, 0x7c, 0x7d, + 0x7c, 0x7c, 0x84, 0x7e, 0x81, 0x88, 0x82, 0x84, 0x84, 0x80, 0x80, + 0x7e, 0x7b, 0x7d, 0x7a, 0x78, 0x7c, 0x7c, 0x7d, 0x80, 0x83, 0x84, + 0x84, 0x84, 0x86, 0x85, 0x82, 0x85, 0x83, 0x81, 0x82, 0x83, 0x83, + 0x82, 0x87, 0x84, 0x8c, 0x62, 0x66, 0x8f, 0x4c, 0x64, 0x82, 0x66, + 0x71, 0x79, 0x84, 0x82, 0x8c, 0x85, 0x93, 0x95, 0x80, 0x8f, 0x8f, + 0x83, 0x83, 0x8a, 0x81, 0x80, 0x83, 0x7c, 0x82, 0x7d, 0x77, 0x7e, + 0x7c, 0x73, 0x7a, 0x7f, 0x7b, 0x7e, 0x82, 0x82, 0x83, 0x7f, 0x86, + 0x87, 0x7f, 0x83, 0x83, 0x80, 0x7c, 0x7e, 0x7e, 0x7b, 0x79, 0x79, + 0x7e, 0x7c, 0x7c, 0x82, 0x84, 0x81, 0x83, 0x86, 0x85, 0x83, 0x82, + 0x85, 0x83, 0x82, 0x83, 0x84, 0x83, 0x82, 0x88, 0x85, 0x87, 0x68, + 0x66, 0x8a, 0x5b, 0x5d, 0x7c, 0x6e, 0x70, 0x6f, 0x85, 0x83, 0x84, + 0x87, 0x89, 0x9a, 0x87, 0x85, 0x93, 0x8f, 0x85, 0x85, 0x8b, 0x82, + 0x80, 0x80, 0x7c, 0x7f, 0x7a, 0x76, 0x7a, 0x7a, 0x78, 0x7a, 0x80, + 0x7f, 0x80, 0x81, 0x80, 0x87, 0x84, 0x80, 0x84, 0x84, 0x80, 0x7f, + 0x80, 0x7f, 0x7e, 0x7c, 0x7b, 0x7c, 0x7a, 0x79, 0x7c, 0x7e, 0x7f, + 0x7e, 0x82, 0x84, 0x83, 0x85, 0x85, 0x87, 0x86, 0x84, 0x86, 0x85, + 0x85, 0x83, 0x84, 0x84, 0x83, 0x81, 0x82, 0x75, 0x61, 0x75, 0x76, + 0x62, 0x68, 0x6f, 0x7c, 0x73, 0x71, 0x84, 0x86, 0x8a, 0x86, 0x8c, + 0x91, 0x8d, 0x8f, 0x8a, 0x8a, 0x8c, 0x8a, 0x84, 0x7e, 0x84, 0x85, + 0x7c, 0x7b, 0x7c, 0x7c, 0x7b, 0x78, 0x79, 0x7c, 0x7c, 0x7c, 0x7c, + 0x7d, 0x80, 0x81, 0x81, 0x7f, 0x80, 0x82, 0x82, 0x82, 0x80, 0x81, + 0x81, 0x80, 0x7e, 0x7e, 0x7c, 0x7c, 0x7e, 0x7d, 0x7f, 0x7e, 0x80, + 0x84, 0x81, 0x83, 0x83, 0x82, 0x82, 0x80, 0x7f, 0x80, 0x80, 0x80, + 0x80, 0x7f, 0x81, 0x83, 0x81, 0x83, 0x83, 0x81, 0x7c, 0x79, 0x7d, + 0x7c, 0x72, 0x72, 0x7a, 0x73, 0x71, 0x79, 0x78, 0x78, 0x7d, 0x84, + 0x82, 0x81, 0x89, 0x8c, 0x89, 0x8a, 0x8f, 0x8b, 0x87, 0x8b, 0x88, + 0x85, 0x85, 0x85, 0x82, 0x7f, 0x7f, 0x7e, 0x7e, 0x7b, 0x7a, 0x7a, + 0x7a, 0x79, 0x78, 0x7a, 0x7a, 0x79, 0x7c, 0x7d, 0x7b, 0x7d, 0x81, + 0x80, 0x80, 0x81, 0x83, 0x83, 0x83, 0x84, 0x83, 0x83, 0x83, 0x83, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x80, 0x80, 0x81, 0x7f, 0x80, 0x81, + 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x81, 0x83, 0x82, 0x83, 0x7e, + 0x78, 0x7e, 0x7d, 0x75, 0x71, 0x78, 0x77, 0x70, 0x76, 0x7a, 0x79, + 0x7b, 0x83, 0x84, 0x80, 0x87, 0x8c, 0x89, 0x88, 0x8c, 0x8d, 0x88, + 0x89, 0x89, 0x86, 0x85, 0x84, 0x82, 0x82, 0x80, 0x7e, 0x7f, 0x7d, + 0x7b, 0x7a, 0x7b, 0x79, 0x78, 0x79, 0x7a, 0x7a, 0x7b, 0x7d, 0x7e, + 0x7e, 0x80, 0x81, 0x81, 0x81, 0x80, 0x81, 0x81, 0x80, 0x7f, 0x80, + 0x82, 0x80, 0x80, 0x81, 0x81, 0x80, 0x82, 0x81, 0x80, 0x81, 0x82, + 0x82, 0x80, 0x81, 0x82, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x81, 0x82, 0x82, 0x83, 0x83, 0x82, 0x82, 0x80, 0x79, 0x79, 0x7d, + 0x76, 0x6e, 0x74, 0x77, 0x70, 0x73, 0x79, 0x79, 0x7a, 0x81, 0x86, + 0x82, 0x85, 0x8d, 0x8c, 0x8a, 0x8c, 0x8e, 0x8b, 0x89, 0x8a, 0x88, + 0x86, 0x85, 0x84, 0x82, 0x80, 0x7d, 0x7d, 0x7b, 0x79, 0x78, 0x77, + 0x78, 0x76, 0x76, 0x79, 0x79, 0x7a, 0x7d, 0x7f, 0x7f, 0x81, 0x83, + 0x83, 0x84, 0x84, 0x84, 0x83, 0x82, 0x83, 0x81, 0x7f, 0x80, 0x7f, + 0x7e, 0x7e, 0x7e, 0x7d, 0x7d, 0x7d, 0x7e, 0x7d, 0x7e, 0x7f, 0x7f, + 0x80, 0x81, 0x83, 0x83, 0x83, 0x84, 0x85, 0x84, 0x84, 0x83, 0x83, + 0x82, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7d, + 0x79, 0x7a, 0x7d, 0x78, 0x71, 0x75, 0x79, 0x73, 0x74, 0x7a, 0x7a, + 0x7b, 0x81, 0x84, 0x82, 0x86, 0x8c, 0x8c, 0x8a, 0x8b, 0x8d, 0x8a, + 0x89, 0x88, 0x86, 0x84, 0x84, 0x83, 0x80, 0x80, 0x7e, 0x7e, 0x7d, + 0x7b, 0x7a, 0x7a, 0x7a, 0x78, 0x79, 0x7a, 0x79, 0x79, 0x7c, 0x7d, + 0x7d, 0x7f, 0x81, 0x82, 0x82, 0x83, 0x84, 0x84, 0x83, 0x83, 0x82, + 0x81, 0x81, 0x80, 0x7e, 0x7e, 0x7d, 0x7d, 0x7c, 0x7c, 0x7c, 0x7d, + 0x7e, 0x7f, 0x80, 0x80, 0x82, 0x84, 0x83, 0x83, 0x85, 0x84, 0x84, + 0x83, 0x83, 0x83, 0x81, 0x81, 0x81, 0x80, 0x7f, 0x7f, 0x7e, 0x7d, + 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7c, 0x79, 0x78, + 0x7b, 0x79, 0x75, 0x77, 0x7a, 0x78, 0x79, 0x7d, 0x7e, 0x7f, 0x83, + 0x86, 0x85, 0x87, 0x8b, 0x8b, 0x8a, 0x8b, 0x8b, 0x89, 0x88, 0x87, + 0x86, 0x83, 0x82, 0x81, 0x7e, 0x7c, 0x7c, 0x7b, 0x7a, 0x79, 0x78, + 0x79, 0x79, 0x78, 0x7a, 0x7b, 0x7b, 0x7c, 0x7e, 0x7f, 0x80, 0x82, + 0x82, 0x83, 0x83, 0x82, 0x82, 0x82, 0x81, 0x80, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7e, 0x7e, 0x7f, 0x7e, 0x7f, 0x7f, 0x7e, 0x80, 0x80, 0x80, + 0x80, 0x81, 0x81, 0x81, 0x81, 0x81, 0x82, 0x81, 0x82, 0x81, 0x82, + 0x81, 0x80, 0x80, 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, 0x7d, 0x7d, 0x7d, + 0x7d, 0x7d, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x80, 0x81, 0x81, 0x81, + 0x82, 0x82, 0x81, 0x7e, 0x7e, 0x7e, 0x7c, 0x7a, 0x7b, 0x7c, 0x7b, + 0x7b, 0x7d, 0x7e, 0x7e, 0x81, 0x82, 0x81, 0x82, 0x84, 0x84, 0x83, + 0x84, 0x84, 0x83, 0x83, 0x83, 0x82, 0x82, 0x81, 0x81, 0x80, 0x7f, + 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, + 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, + }, + { // 8 + 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, + 0x7e, 0x7d, 0x7d, 0x7d, 0x7d, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x80, + 0x80, 0x80, 0x81, 0x81, 0x82, 0x82, 0x82, 0x82, 0x82, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x81, 0x81, + 0x81, 0x80, 0x80, 0x7f, 0x7d, 0x7c, 0x79, 0x78, 0x78, 0x78, 0x7a, + 0x7d, 0x7f, 0x81, 0x83, 0x83, 0x84, 0x84, 0x85, 0x85, 0x86, 0x85, + 0x84, 0x83, 0x81, 0x80, 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, 0x7c, 0x7c, + 0x7b, 0x7c, 0x7d, 0x80, 0x82, 0x83, 0x84, 0x84, 0x82, 0x81, 0x81, + 0x80, 0x81, 0x82, 0x82, 0x83, 0x83, 0x84, 0x84, 0x83, 0x85, 0x87, + 0x88, 0x8a, 0x84, 0x73, 0x6c, 0x61, 0x53, 0x5d, 0x66, 0x6e, 0x81, + 0x8b, 0x8e, 0x8e, 0x8d, 0x8f, 0x8e, 0x93, 0x9a, 0x96, 0x8f, 0x8a, + 0x7b, 0x6e, 0x6d, 0x6a, 0x6e, 0x79, 0x82, 0x87, 0x88, 0x89, 0x86, + 0x80, 0x85, 0x88, 0x87, 0x8a, 0x89, 0x7f, 0x78, 0x72, 0x6c, 0x6b, + 0x70, 0x76, 0x7a, 0x7f, 0x83, 0x83, 0x86, 0x8a, 0x8c, 0x8f, 0x8f, + 0x8b, 0x86, 0x81, 0x7f, 0x7e, 0x81, 0x85, 0x86, 0x8a, 0x8c, 0x8b, + 0x8a, 0x8a, 0x78, 0x5f, 0x59, 0x48, 0x42, 0x5a, 0x68, 0x78, 0x8e, + 0x96, 0x98, 0x97, 0x9c, 0x9f, 0x9d, 0xa2, 0x9f, 0x8a, 0x7b, 0x6f, + 0x5a, 0x58, 0x63, 0x6b, 0x7a, 0x87, 0x90, 0x90, 0x8d, 0x93, 0x90, + 0x8f, 0x97, 0x91, 0x85, 0x7e, 0x6e, 0x5f, 0x5a, 0x5c, 0x62, 0x6c, + 0x7d, 0x88, 0x8f, 0x99, 0x9a, 0x98, 0x99, 0x93, 0x8b, 0x84, 0x7f, + 0x79, 0x77, 0x7b, 0x7e, 0x82, 0x89, 0x8d, 0x8d, 0x91, 0x7b, 0x59, + 0x56, 0x43, 0x3f, 0x60, 0x6f, 0x7e, 0x8f, 0x92, 0x94, 0x93, 0x9f, + 0xab, 0xa5, 0xa5, 0x9c, 0x7a, 0x66, 0x5f, 0x54, 0x5f, 0x71, 0x7d, + 0x84, 0x84, 0x8c, 0x8a, 0x8c, 0xa0, 0xa0, 0x99, 0x96, 0x82, 0x6c, + 0x62, 0x5f, 0x60, 0x64, 0x6e, 0x72, 0x72, 0x7f, 0x8a, 0x95, 0xa3, + 0xa6, 0x9e, 0x90, 0x84, 0x7a, 0x74, 0x7c, 0x80, 0x81, 0x82, 0x80, + 0x7e, 0x86, 0x8f, 0x99, 0x96, 0x66, 0x4f, 0x44, 0x2b, 0x4d, 0x73, + 0x7f, 0x8f, 0x8e, 0x8f, 0x8e, 0x99, 0xba, 0xba, 0xaa, 0xa0, 0x77, + 0x53, 0x55, 0x5b, 0x6b, 0x78, 0x7e, 0x7e, 0x6e, 0x7d, 0x96, 0x9d, + 0xb2, 0xb2, 0x96, 0x7a, 0x63, 0x60, 0x62, 0x6f, 0x7c, 0x6e, 0x65, + 0x66, 0x6f, 0x87, 0xa0, 0xb0, 0xa5, 0x92, 0x86, 0x79, 0x7f, 0x8a, + 0x8b, 0x82, 0x75, 0x6e, 0x6e, 0x7f, 0x94, 0x9d, 0x9d, 0x9f, 0x71, + 0x35, 0x42, 0x45, 0x49, 0x74, 0x7b, 0x72, 0x68, 0x7d, 0xa5, 0xaf, + 0xca, 0xd1, 0x9d, 0x7b, 0x76, 0x6d, 0x6f, 0x72, 0x73, 0x5d, 0x47, + 0x68, 0x80, 0x91, 0xae, 0xab, 0x95, 0x85, 0x8d, 0x92, 0x89, 0x8b, + 0x76, 0x58, 0x54, 0x5f, 0x6b, 0x75, 0x84, 0x84, 0x80, 0x91, 0x9f, + 0xa0, 0x9c, 0x93, 0x81, 0x74, 0x7b, 0x7f, 0x7a, 0x79, 0x76, 0x74, + 0x7c, 0x8c, 0x95, 0x92, 0x9c, 0x7a, 0x3b, 0x42, 0x51, 0x5a, 0x6d, + 0x72, 0x70, 0x68, 0x8b, 0xb1, 0xb0, 0xb3, 0xa7, 0x91, 0x87, 0x8b, + 0x8e, 0x75, 0x5e, 0x5a, 0x5c, 0x6c, 0x82, 0x8a, 0x83, 0x86, 0x95, + 0x9e, 0xa1, 0x9a, 0x86, 0x74, 0x74, 0x7a, 0x77, 0x6c, 0x61, 0x5f, + 0x6d, 0x83, 0x91, 0x90, 0x8b, 0x8d, 0x92, 0x98, 0x95, 0x87, 0x77, + 0x73, 0x7a, 0x7f, 0x7d, 0x78, 0x74, 0x7b, 0x8a, 0x99, 0x96, 0x72, + 0x4c, 0x4f, 0x62, 0x6c, 0x6b, 0x62, 0x5f, 0x70, 0x94, 0xa4, 0x9a, + 0x91, 0x94, 0x9c, 0x9f, 0x9a, 0x88, 0x73, 0x74, 0x7c, 0x79, 0x73, + 0x70, 0x73, 0x7d, 0x8d, 0x91, 0x88, 0x86, 0x8a, 0x8a, 0x87, 0x82, + 0x7a, 0x74, 0x78, 0x7a, 0x75, 0x73, 0x78, 0x7d, 0x81, 0x86, 0x88, + 0x89, 0x8d, 0x8f, 0x8a, 0x84, 0x83, 0x80, 0x7c, 0x7b, 0x79, 0x7a, + 0x7e, 0x87, 0x84, 0x75, 0x6b, 0x64, 0x67, 0x67, 0x65, 0x64, 0x68, + 0x75, 0x7e, 0x85, 0x89, 0x90, 0x98, 0x9a, 0x96, 0x91, 0x90, 0x8d, + 0x88, 0x84, 0x7e, 0x7b, 0x7c, 0x7c, 0x7b, 0x7d, 0x82, 0x85, 0x85, + 0x84, 0x84, 0x84, 0x84, 0x85, 0x80, 0x7c, 0x7a, 0x79, 0x77, 0x77, + 0x7b, 0x7b, 0x7d, 0x7e, 0x80, 0x85, 0x89, 0x8a, 0x88, 0x85, 0x83, + 0x81, 0x80, 0x7e, 0x7c, 0x7b, 0x79, 0x7b, 0x7a, 0x76, 0x77, 0x73, + 0x71, 0x6f, 0x6f, 0x70, 0x70, 0x75, 0x78, 0x7b, 0x80, 0x84, 0x87, + 0x8a, 0x8f, 0x90, 0x8f, 0x8e, 0x8c, 0x88, 0x86, 0x85, 0x84, 0x81, + 0x7f, 0x7f, 0x7f, 0x80, 0x81, 0x81, 0x82, 0x84, 0x85, 0x84, 0x82, + 0x81, 0x7f, 0x7d, 0x7d, 0x7c, 0x7b, 0x7a, 0x7a, 0x7b, 0x7d, 0x80, + 0x82, 0x81, 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7d, + 0x80, 0x7e, 0x7e, 0x80, 0x7e, 0x7f, 0x7f, 0x7f, 0x81, 0x81, 0x83, + 0x80, 0x7f, 0x7f, 0x7d, 0x80, 0x7f, 0x7d, 0x80, 0x7e, 0x7e, 0x81, + 0x7f, 0x81, 0x7f, 0x7f, 0x7e, 0x7e, 0x7d, 0x7e, 0x7f, 0x7f, 0x7f, + 0x7e, 0x80, 0x7d, 0x84, 0x82, 0x82, 0x82, 0x7f, 0x81, 0x80, 0x80, + 0x7f, 0x81, 0x7b, 0x7f, 0x7f, 0x80, 0x81, 0x7f, 0x80, 0x7e, 0x7f, + 0x81, 0x7f, 0x82, 0x7f, 0x7e, 0x80, 0x7c, 0x81, 0x7f, 0x7f, 0x7f, + 0x80, 0x7e, 0x7f, 0x82, 0x7f, 0x84, 0x80, 0x81, 0x81, 0x7e, 0x81, + 0x81, 0x7f, 0x80, 0x80, 0x7e, 0x82, 0x7d, 0x80, 0x7e, 0x7c, 0x81, + 0x7c, 0x7f, 0x80, 0x7e, 0x7e, 0x81, 0x7e, 0x81, 0x82, 0x81, 0x80, + 0x82, 0x80, 0x82, 0x81, 0x80, 0x80, 0x7d, 0x81, 0x7d, 0x81, 0x7f, + 0x82, 0x7e, 0x7e, 0x7f, 0x7e, 0x7e, 0x7e, 0x7f, 0x7e, 0x7e, 0x7d, + 0x7f, 0x80, 0x80, 0x7f, 0x84, 0x7e, 0x82, 0x82, 0x7f, 0x80, 0x82, + 0x7d, 0x82, 0x7f, 0x7d, 0x83, 0x7d, 0x81, 0x82, 0x7f, 0x82, 0x81, + 0x7f, 0x80, 0x7f, 0x7d, 0x7f, 0x7c, 0x7e, 0x7c, 0x7d, 0x7f, 0x7e, + 0x83, 0x81, 0x83, 0x81, 0x81, 0x81, 0x81, 0x81, 0x80, 0x81, 0x7c, + 0x80, 0x7c, 0x7f, 0x83, 0x7e, 0x82, 0x82, 0x7e, 0x80, 0x80, 0x7d, + 0x81, 0x7c, 0x7c, 0x80, 0x79, 0x7f, 0x7e, 0x7e, 0x82, 0x7f, 0x82, + 0x81, 0x80, 0x82, 0x81, 0x7f, 0x82, 0x7e, 0x7f, 0x7f, 0x7e, 0x80, + 0x80, 0x7f, 0x80, 0x82, 0x80, 0x81, 0x7f, 0x80, 0x7f, 0x7e, 0x80, + 0x7c, 0x7e, 0x7d, 0x7c, 0x80, 0x80, 0x7e, 0x82, 0x82, 0x80, 0x84, + 0x80, 0x82, 0x81, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x81, + 0x7e, 0x83, 0x7e, 0x7f, 0x80, 0x7b, 0x80, 0x7d, 0x7e, 0x7f, 0x7f, + 0x7c, 0x81, 0x7e, 0x81, 0x83, 0x7f, 0x82, 0x7f, 0x80, 0x7f, 0x7f, + 0x7f, 0x81, 0x7e, 0x80, 0x7e, 0x7c, 0x83, 0x7f, 0x83, 0x80, 0x83, + 0x7d, 0x80, 0x82, 0x7c, 0x82, 0x7d, 0x7c, 0x7d, 0x7d, 0x7c, 0x81, + 0x80, 0x7f, 0x84, 0x7e, 0x82, 0x80, 0x80, 0x81, 0x80, 0x81, 0x7d, + 0x82, 0x7e, 0x7e, 0x83, 0x80, 0x81, 0x80, 0x80, 0x80, 0x7e, 0x81, + 0x7d, 0x7f, 0x7d, 0x7e, 0x7e, 0x7d, 0x7f, 0x83, 0x7f, 0x81, 0x83, + 0x7c, 0x83, 0x7e, 0x7d, 0x82, 0x7e, 0x80, 0x7f, 0x7d, 0x80, 0x7e, + 0x7f, 0x82, 0x80, 0x80, 0x84, 0x7d, 0x83, 0x80, 0x7f, 0x81, 0x7c, + 0x7e, 0x7d, 0x7d, 0x7f, 0x7f, 0x80, 0x81, 0x7e, 0x82, 0x80, 0x80, + 0x82, 0x80, 0x7e, 0x80, 0x81, 0x7d, 0x81, 0x81, 0x7e, 0x82, 0x7f, + 0x83, 0x80, 0x81, 0x7f, 0x7f, 0x7d, 0x7d, 0x7e, 0x7d, 0x7e, 0x7e, + 0x81, 0x80, 0x82, 0x80, 0x84, 0x80, 0x81, 0x80, 0x7f, 0x7f, 0x7e, + 0x7f, 0x7e, 0x7e, 0x7e, 0x80, 0x7f, 0x80, 0x82, 0x81, 0x83, 0x81, + 0x81, 0x81, 0x7f, 0x7f, 0x7e, 0x7f, 0x7e, 0x7e, 0x7d, 0x80, 0x7e, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x7c, + 0x82, 0x7e, 0x80, 0x82, 0x80, 0x81, 0x82, 0x7e, 0x80, 0x7f, 0x7d, + 0x81, 0x7d, 0x7f, 0x80, 0x7b, 0x7e, 0x84, 0x7c, 0x82, 0x82, 0x7d, + 0x84, 0x7f, 0x80, 0x80, 0x7b, 0x80, 0x7f, 0x7f, 0x82, 0x7f, 0x7f, + 0x81, 0x7d, 0x82, 0x81, 0x7f, 0x81, 0x80, 0x7f, 0x80, 0x7e, 0x7e, + 0x7e, 0x7e, 0x80, 0x80, 0x80, 0x7d, 0x80, 0x82, 0x80, 0x7f, 0x7f, + 0x7d, 0x7f, 0x80, 0x80, 0x81, 0x80, 0x7f, 0x81, 0x7e, 0x82, 0x82, + 0x7d, 0x83, 0x7c, 0x81, 0x7d, 0x7f, 0x7f, 0x7d, 0x7f, 0x7e, 0x81, + 0x7f, 0x81, 0x80, 0x82, 0x80, 0x83, 0x7f, 0x7f, 0x80, 0x7d, 0x80, + 0x7f, 0x7d, 0x7e, 0x7f, 0x7e, 0x82, 0x81, 0x80, 0x82, 0x7e, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7e, 0x80, 0x7d, 0x82, 0x7e, 0x82, + 0x80, 0x7e, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7e, 0x7f, + 0x82, 0x80, 0x81, 0x82, 0x7d, 0x82, 0x7b, 0x82, 0x7e, 0x7f, 0x80, + 0x7e, 0x7f, 0x7f, 0x7f, 0x80, 0x83, 0x7c, 0x81, 0x80, 0x7d, 0x83, + 0x7e, 0x83, 0x80, 0x7e, 0x81, 0x7f, 0x7f, 0x7f, 0x81, 0x7c, 0x83, + 0x7d, 0x81, 0x80, 0x7f, 0x80, 0x81, 0x7e, 0x7f, 0x80, 0x7c, 0x82, + 0x7d, 0x81, 0x7f, 0x7f, 0x7f, 0x81, 0x7f, 0x80, 0x7f, 0x7d, 0x81, + 0x7c, 0x80, 0x81, 0x7d, 0x82, 0x81, 0x7f, 0x84, 0x7d, 0x81, 0x80, + 0x7d, 0x81, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7e, 0x81, 0x7f, + 0x7e, 0x82, 0x7e, 0x7f, 0x81, 0x7a, 0x82, 0x81, 0x7d, 0x83, 0x7e, + 0x7f, 0x80, 0x7f, 0x7e, 0x81, 0x7d, 0x81, 0x81, 0x7f, 0x80, 0x80, + 0x82, 0x7d, 0x82, 0x7e, 0x7e, 0x81, 0x7f, 0x80, 0x82, 0x7e, 0x7d, + 0x81, 0x7c, 0x81, 0x7f, 0x7d, 0x81, 0x7c, 0x80, 0x80, 0x80, 0x81, + 0x81, 0x7d, 0x81, 0x81, 0x7c, 0x84, 0x80, 0x7e, 0x81, 0x7f, 0x7c, + 0x83, 0x7d, 0x81, 0x80, 0x7d, 0x80, 0x7e, 0x7e, 0x7f, 0x81, 0x7d, + 0x80, 0x7f, 0x80, 0x81, 0x7f, 0x82, 0x80, 0x81, 0x80, 0x7d, 0x82, + 0x7e, 0x7f, 0x83, 0x7e, 0x82, 0x81, 0x7f, 0x82, 0x7f, 0x7d, 0x7f, + 0x7d, 0x7c, 0x81, 0x7c, 0x7e, 0x80, 0x7d, 0x7f, 0x80, 0x7f, 0x81, + 0x80, 0x7f, 0x82, 0x7f, 0x80, 0x82, 0x7f, 0x7f, 0x81, 0x7c, 0x7f, + 0x80, 0x7e, 0x81, 0x80, 0x7d, 0x80, 0x80, 0x7c, 0x83, 0x7e, 0x81, + 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x7e, 0x80, 0x7e, 0x81, 0x7e, 0x81, + 0x7d, 0x81, 0x80, 0x7e, 0x81, 0x7e, 0x7d, 0x7f, 0x7f, 0x7f, 0x80, + 0x7f, 0x80, 0x80, 0x82, 0x80, 0x81, 0x80, 0x7f, 0x7d, 0x7f, 0x7f, + 0x7e, 0x81, 0x7d, 0x81, 0x7d, 0x7e, 0x80, 0x7f, 0x81, 0x7f, 0x80, + 0x80, 0x80, 0x7f, 0x81, 0x7d, 0x80, 0x7f, 0x7e, 0x81, 0x7e, 0x80, + 0x81, 0x80, 0x80, 0x82, 0x7e, 0x80, 0x7f, 0x7e, 0x80, 0x7e, 0x7d, + 0x7f, 0x7d, 0x7e, 0x81, 0x7f, 0x81, 0x81, 0x7f, 0x80, 0x80, 0x7f, + 0x81, 0x7e, 0x80, 0x80, 0x7d, 0x81, 0x7f, 0x7e, 0x81, 0x7e, 0x7e, + 0x82, 0x7e, 0x81, 0x80, 0x7e, 0x81, 0x7e, 0x7f, 0x80, 0x7e, 0x80, + 0x7f, 0x7e, 0x81, 0x7e, 0x80, 0x80, 0x80, 0x81, 0x81, 0x7e, 0x81, + 0x7f, 0x7e, 0x82, 0x7e, 0x80, 0x81, 0x7f, 0x81, 0x80, 0x7e, 0x80, + 0x7e, 0x7b, 0x7b, 0x7a, 0x77, 0x79, 0x79, 0x79, 0x7c, 0x7c, 0x7d, + 0x80, 0x81, 0x83, 0x86, 0x86, 0x88, 0x88, 0x87, 0x87, 0x86, 0x86, + 0x84, 0x83, 0x81, 0x80, 0x7e, 0x7e, 0x7c, 0x7c, 0x7b, 0x7a, 0x7a, + 0x7b, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x82, 0x82, 0x83, 0x84, + 0x84, 0x84, 0x84, 0x85, 0x82, 0x83, 0x81, 0x81, 0x81, 0x80, 0x7f, + 0x80, 0x7e, 0x81, 0x7f, 0x83, 0x77, 0x6d, 0x88, 0x69, 0x6a, 0x7a, + 0x65, 0x77, 0x6e, 0x6d, 0x80, 0x7a, 0x7c, 0x88, 0x8c, 0x8d, 0x90, + 0x91, 0x93, 0x98, 0x8e, 0x8e, 0x93, 0x86, 0x85, 0x83, 0x7e, 0x7e, + 0x77, 0x76, 0x79, 0x76, 0x74, 0x77, 0x78, 0x79, 0x7a, 0x7a, 0x7f, + 0x80, 0x7e, 0x82, 0x84, 0x82, 0x84, 0x83, 0x83, 0x85, 0x80, 0x7d, + 0x80, 0x7e, 0x76, 0x7b, 0x7b, 0x79, 0x7a, 0x7b, 0x7f, 0x7f, 0x80, + 0x85, 0x87, 0x85, 0x88, 0x89, 0x89, 0x87, 0x86, 0x87, 0x85, 0x82, + 0x82, 0x84, 0x7f, 0x80, 0x80, 0x81, 0x83, 0x7d, 0x7f, 0x63, 0x7c, + 0x78, 0x49, 0x7f, 0x64, 0x5a, 0x7a, 0x5d, 0x7c, 0x7f, 0x75, 0x8b, + 0x92, 0x95, 0x8f, 0x9e, 0x9a, 0x94, 0x9e, 0x8b, 0x96, 0x94, 0x7a, + 0x8a, 0x83, 0x76, 0x7b, 0x75, 0x78, 0x74, 0x73, 0x72, 0x77, 0x7a, + 0x71, 0x7f, 0x7f, 0x7b, 0x83, 0x7f, 0x86, 0x86, 0x81, 0x88, 0x86, + 0x83, 0x7f, 0x80, 0x82, 0x79, 0x7a, 0x7d, 0x78, 0x77, 0x79, 0x7c, + 0x7b, 0x7c, 0x7f, 0x83, 0x84, 0x83, 0x89, 0x8a, 0x88, 0x89, 0x8a, + 0x89, 0x87, 0x86, 0x86, 0x83, 0x80, 0x7f, 0x80, 0x7f, 0x7c, 0x81, + 0x7f, 0x81, 0x6b, 0x66, 0x8d, 0x51, 0x57, 0x8a, 0x4d, 0x68, 0x74, + 0x65, 0x84, 0x77, 0x88, 0x8d, 0x9a, 0xa1, 0x85, 0xaa, 0xa4, 0x8a, + 0xa2, 0x95, 0x8c, 0x8b, 0x7e, 0x81, 0x7f, 0x77, 0x74, 0x73, 0x7a, + 0x6e, 0x6c, 0x7d, 0x75, 0x75, 0x7b, 0x7a, 0x82, 0x7d, 0x7f, 0x86, + 0x84, 0x87, 0x83, 0x86, 0x8a, 0x83, 0x83, 0x83, 0x83, 0x7c, 0x76, + 0x7d, 0x79, 0x72, 0x76, 0x77, 0x77, 0x76, 0x7b, 0x81, 0x80, 0x84, + 0x86, 0x89, 0x8c, 0x89, 0x8b, 0x8c, 0x8b, 0x88, 0x86, 0x86, 0x83, + 0x80, 0x80, 0x7e, 0x7d, 0x7c, 0x7c, 0x7d, 0x7f, 0x80, 0x7e, 0x80, + 0x74, 0x69, 0x79, 0x72, 0x65, 0x67, 0x6b, 0x76, 0x6a, 0x6a, 0x82, + 0x83, 0x81, 0x89, 0x92, 0x94, 0x8f, 0x96, 0x9a, 0x92, 0x92, 0x94, + 0x8e, 0x86, 0x86, 0x86, 0x81, 0x7d, 0x7d, 0x7c, 0x79, 0x78, 0x79, + 0x7a, 0x78, 0x76, 0x78, 0x7b, 0x79, 0x79, 0x7c, 0x7e, 0x7c, 0x7d, + 0x81, 0x82, 0x80, 0x83, 0x84, 0x82, 0x82, 0x83, 0x82, 0x7f, 0x7e, + 0x80, 0x7d, 0x79, 0x7a, 0x7c, 0x7a, 0x7b, 0x7e, 0x7e, 0x7e, 0x81, + 0x82, 0x83, 0x84, 0x86, 0x87, 0x86, 0x86, 0x87, 0x87, 0x86, 0x85, + 0x84, 0x83, 0x81, 0x81, 0x7f, 0x7f, 0x7e, 0x7e, 0x7f, 0x7f, 0x80, + 0x7f, 0x80, 0x7e, 0x71, 0x71, 0x79, 0x71, 0x64, 0x69, 0x74, 0x6d, + 0x68, 0x77, 0x7c, 0x79, 0x83, 0x8e, 0x8b, 0x88, 0x94, 0x9a, 0x94, + 0x92, 0x96, 0x94, 0x8d, 0x8c, 0x8c, 0x88, 0x83, 0x82, 0x81, 0x7e, + 0x7a, 0x79, 0x7a, 0x78, 0x72, 0x74, 0x77, 0x74, 0x72, 0x77, 0x79, + 0x76, 0x79, 0x7e, 0x7e, 0x7e, 0x81, 0x85, 0x83, 0x83, 0x85, 0x86, + 0x84, 0x84, 0x84, 0x81, 0x80, 0x7f, 0x7e, 0x7d, 0x7c, 0x7c, 0x7c, + 0x7c, 0x7c, 0x7e, 0x80, 0x80, 0x82, 0x84, 0x84, 0x85, 0x86, 0x86, + 0x86, 0x85, 0x86, 0x85, 0x82, 0x81, 0x81, 0x80, 0x7f, 0x7f, 0x7f, + 0x7e, 0x7f, 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, 0x75, 0x6c, 0x74, 0x76, + 0x68, 0x64, 0x71, 0x73, 0x6a, 0x73, 0x7f, 0x7d, 0x82, 0x8c, 0x90, + 0x8b, 0x90, 0x9a, 0x97, 0x92, 0x94, 0x96, 0x91, 0x8e, 0x8c, 0x89, + 0x86, 0x82, 0x7f, 0x7d, 0x78, 0x74, 0x75, 0x74, 0x70, 0x6f, 0x73, + 0x74, 0x72, 0x75, 0x7a, 0x7a, 0x7b, 0x80, 0x83, 0x82, 0x85, 0x88, + 0x87, 0x86, 0x87, 0x86, 0x85, 0x83, 0x81, 0x7f, 0x7d, 0x7d, 0x7c, + 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7b, 0x7d, 0x7f, 0x80, 0x82, 0x83, + 0x85, 0x86, 0x87, 0x87, 0x88, 0x87, 0x86, 0x86, 0x84, 0x83, 0x83, + 0x81, 0x7f, 0x7e, 0x7d, 0x7c, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7d, + 0x7d, 0x7e, 0x7e, 0x7f, 0x7b, 0x72, 0x75, 0x7b, 0x73, 0x6b, 0x72, + 0x7a, 0x73, 0x74, 0x7f, 0x82, 0x81, 0x89, 0x8e, 0x89, 0x8b, 0x93, + 0x93, 0x8f, 0x8e, 0x90, 0x8d, 0x89, 0x89, 0x86, 0x84, 0x81, 0x7e, + 0x7c, 0x7a, 0x77, 0x77, 0x78, 0x76, 0x73, 0x76, 0x78, 0x77, 0x78, + 0x7b, 0x7d, 0x7d, 0x7f, 0x81, 0x81, 0x81, 0x83, 0x83, 0x82, 0x81, + 0x80, 0x80, 0x81, 0x7f, 0x7e, 0x7f, 0x80, 0x7d, 0x7d, 0x7f, 0x7e, + 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x83, 0x82, 0x82, 0x84, 0x84, 0x83, + 0x83, 0x83, 0x83, 0x82, 0x81, 0x81, 0x7f, 0x7e, 0x7e, 0x7e, 0x7d, + 0x7c, 0x7c, 0x7e, 0x7d, 0x7d, 0x7e, 0x7f, 0x80, 0x80, 0x81, 0x81, + 0x82, 0x81, 0x80, 0x80, 0x7d, 0x77, 0x75, 0x78, 0x76, 0x70, 0x72, + 0x78, 0x76, 0x76, 0x7d, 0x81, 0x81, 0x85, 0x8a, 0x89, 0x8a, 0x8e, + 0x90, 0x8d, 0x8c, 0x8d, 0x8c, 0x89, 0x87, 0x86, 0x84, 0x83, 0x80, + 0x7f, 0x7d, 0x7a, 0x79, 0x78, 0x77, 0x75, 0x75, 0x76, 0x76, 0x77, + 0x79, 0x7b, 0x7c, 0x7e, 0x80, 0x81, 0x82, 0x84, 0x84, 0x82, 0x82, + 0x82, 0x81, 0x7e, 0x7d, 0x7f, 0x7e, 0x7d, 0x7e, 0x80, 0x7f, 0x7f, + 0x81, 0x81, 0x80, 0x81, 0x83, 0x82, 0x82, 0x83, 0x83, 0x83, 0x83, + 0x84, 0x83, 0x82, 0x82, 0x81, 0x80, 0x7f, 0x7f, 0x7e, 0x7c, 0x7b, + 0x7b, 0x7b, 0x7a, 0x7b, 0x7c, 0x7c, 0x7d, 0x7e, 0x7e, 0x7f, 0x7f, + 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, + 0x7e, 0x7d, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x80, 0x81, 0x82, 0x82, + 0x83, 0x83, 0x83, 0x84, 0x84, 0x83, 0x84, 0x83, 0x81, 0x81, 0x80, + 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7e, 0x7e, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7c, 0x7d, 0x7e, + 0x7e, 0x7f, 0x80, 0x80, 0x81, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x81, 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, + 0x7e, 0x7e, 0x7d, 0x7e, 0x7d, 0x79, 0x78, 0x7a, 0x78, 0x76, 0x76, + 0x79, 0x79, 0x79, 0x7d, 0x7f, 0x81, 0x83, 0x87, 0x88, 0x88, 0x8b, + 0x8c, 0x8b, 0x8b, 0x8b, 0x8a, 0x88, 0x86, 0x85, 0x83, 0x81, 0x7f, + 0x7e, 0x7c, 0x7a, 0x7a, 0x79, 0x79, 0x78, 0x78, 0x7a, 0x7a, 0x7a, + 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x80, 0x81, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x81, 0x81, 0x80, 0x7f, 0x7f, 0x7d, 0x7c, 0x7d, 0x7c, + 0x7c, 0x7c, 0x7c, 0x7d, 0x7e, 0x7e, 0x7f, 0x80, 0x81, 0x81, 0x82, + 0x83, 0x83, 0x83, 0x83, 0x84, 0x83, 0x83, 0x82, 0x81, 0x80, 0x7f, + 0x7e, 0x7e, 0x7d, 0x7d, 0x7c, 0x7c, 0x7c, 0x7c, 0x7d, 0x7d, 0x7d, + 0x7e, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, 0x80, 0x7f, + 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x80, 0x80, + 0x81, 0x81, 0x82, 0x82, 0x82, 0x82, 0x81, 0x81, 0x81, 0x80, 0x7f, + 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, + 0x7f, 0x80, 0x80, 0x80, 0x80, 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, + }, + { // 9 + 0x7f, 0x7e, 0x81, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, + 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, + 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x80, + 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, + 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, + 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, + 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x80, + 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, + 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, + 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x80, + 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, + 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, + 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x80, + 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, + 0x80, 0x7f, 0x80, 0x7f, 0x81, 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x80, + 0x7f, 0x7f, 0x81, 0x7f, 0x81, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x80, + 0x7f, 0x7f, 0x80, 0x7e, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, + 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7e, 0x80, 0x7f, 0x7f, 0x80, + 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x80, + 0x7f, 0x80, 0x80, 0x7e, 0x81, 0x7d, 0x7f, 0x7f, 0x7e, 0x7e, 0x7f, + 0x7d, 0x7f, 0x7f, 0x7d, 0x80, 0x7e, 0x7f, 0x80, 0x7f, 0x81, 0x80, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x82, 0x81, 0x82, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x7e, 0x7f, 0x7e, 0x7e, + 0x7e, 0x7e, 0x7f, 0x7d, 0x7e, 0x7d, 0x7e, 0x7e, 0x80, 0x7e, 0x7f, + 0x7e, 0x7e, 0x7e, 0x83, 0x84, 0x82, 0x81, 0x82, 0x80, 0x7e, 0x84, + 0x7e, 0x81, 0x81, 0x7d, 0x7f, 0x7f, 0x7d, 0x81, 0x7f, 0x7e, 0x82, + 0x7c, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x81, 0x7d, 0x7f, 0x7c, 0x7f, + 0x7c, 0x7c, 0x7e, 0x7c, 0x7d, 0x7d, 0x7c, 0x7f, 0x7f, 0x7d, 0x81, + 0x80, 0x81, 0x82, 0x80, 0x84, 0x82, 0x82, 0x85, 0x81, 0x84, 0x83, + 0x81, 0x82, 0x82, 0x81, 0x81, 0x82, 0x80, 0x80, 0x7f, 0x7d, 0x80, + 0x7e, 0x7c, 0x7f, 0x7b, 0x7d, 0x7b, 0x7c, 0x7d, 0x7c, 0x7d, 0x7f, + 0x7e, 0x7f, 0x80, 0x7f, 0x83, 0x80, 0x83, 0x83, 0x80, 0x83, 0x81, + 0x81, 0x84, 0x81, 0x7f, 0x83, 0x7e, 0x7f, 0x81, 0x7e, 0x80, 0x7e, + 0x7e, 0x80, 0x7d, 0x7f, 0x7f, 0x80, 0x82, 0x7f, 0x82, 0x76, 0x7c, + 0x85, 0x6f, 0x7e, 0x7b, 0x72, 0x82, 0x6e, 0x7a, 0x84, 0x74, 0x83, + 0x7f, 0x83, 0x88, 0x82, 0x88, 0x8a, 0x8a, 0x84, 0x8a, 0x87, 0x84, + 0x87, 0x7e, 0x87, 0x82, 0x7a, 0x84, 0x7c, 0x7d, 0x7f, 0x77, 0x80, + 0x7c, 0x79, 0x7d, 0x7e, 0x7c, 0x7a, 0x7b, 0x7e, 0x7a, 0x7b, 0x7f, + 0x7e, 0x7e, 0x7f, 0x82, 0x83, 0x81, 0x84, 0x86, 0x84, 0x84, 0x84, + 0x86, 0x82, 0x80, 0x83, 0x81, 0x7e, 0x7f, 0x7e, 0x7f, 0x7d, 0x7b, + 0x80, 0x7f, 0x7d, 0x80, 0x80, 0x84, 0x80, 0x87, 0x77, 0x72, 0x90, + 0x67, 0x74, 0x81, 0x62, 0x85, 0x6b, 0x6c, 0x8d, 0x6e, 0x80, 0x88, + 0x81, 0x91, 0x88, 0x8b, 0x95, 0x90, 0x86, 0x91, 0x8c, 0x83, 0x8a, + 0x7a, 0x85, 0x80, 0x70, 0x84, 0x76, 0x77, 0x7d, 0x72, 0x81, 0x7c, + 0x75, 0x82, 0x80, 0x7a, 0x83, 0x7e, 0x81, 0x81, 0x79, 0x84, 0x7d, + 0x7b, 0x82, 0x7e, 0x81, 0x80, 0x7f, 0x87, 0x81, 0x81, 0x8a, 0x82, + 0x85, 0x84, 0x83, 0x85, 0x7f, 0x81, 0x82, 0x7d, 0x7e, 0x7e, 0x7c, + 0x80, 0x7b, 0x81, 0x81, 0x82, 0x82, 0x89, 0x7b, 0x60, 0x9b, 0x65, + 0x5e, 0x8f, 0x4f, 0x86, 0x6c, 0x59, 0x9d, 0x68, 0x7c, 0x94, 0x81, + 0x9b, 0x8e, 0x8f, 0xa1, 0x97, 0x86, 0x99, 0x92, 0x7e, 0x8c, 0x73, + 0x83, 0x7c, 0x60, 0x82, 0x6f, 0x6c, 0x78, 0x70, 0x7f, 0x7c, 0x75, + 0x89, 0x89, 0x7a, 0x8c, 0x88, 0x85, 0x87, 0x7c, 0x89, 0x7c, 0x75, + 0x80, 0x79, 0x78, 0x7b, 0x7c, 0x83, 0x7d, 0x81, 0x8d, 0x84, 0x87, + 0x8b, 0x88, 0x88, 0x82, 0x84, 0x84, 0x7a, 0x7b, 0x7f, 0x77, 0x7a, + 0x7a, 0x7d, 0x86, 0x7b, 0x8e, 0x56, 0x80, 0x9e, 0x30, 0x96, 0x70, + 0x58, 0x98, 0x44, 0x93, 0x8e, 0x60, 0x9d, 0x8f, 0x90, 0x97, 0x90, + 0x9a, 0x9e, 0x84, 0x86, 0x9e, 0x74, 0x7b, 0x7f, 0x6e, 0x83, 0x5f, + 0x74, 0x82, 0x66, 0x78, 0x80, 0x81, 0x7f, 0x82, 0x89, 0x8f, 0x81, + 0x85, 0x8f, 0x81, 0x7f, 0x7e, 0x80, 0x77, 0x6f, 0x79, 0x7a, 0x72, + 0x78, 0x82, 0x82, 0x81, 0x86, 0x8f, 0x8a, 0x85, 0x8e, 0x8c, 0x83, + 0x82, 0x82, 0x81, 0x78, 0x79, 0x7f, 0x77, 0x79, 0x76, 0x89, 0x7e, + 0x90, 0x6c, 0x53, 0xbf, 0x42, 0x5e, 0xa0, 0x3f, 0x98, 0x5b, 0x68, + 0xb0, 0x62, 0x86, 0xa2, 0x92, 0x94, 0x92, 0x97, 0x9c, 0x8e, 0x75, + 0x95, 0x86, 0x62, 0x7f, 0x6e, 0x79, 0x6e, 0x65, 0x8b, 0x78, 0x73, + 0x86, 0x91, 0x82, 0x86, 0x8c, 0x8d, 0x8a, 0x77, 0x88, 0x82, 0x72, + 0x75, 0x77, 0x76, 0x70, 0x70, 0x7e, 0x7e, 0x76, 0x88, 0x8d, 0x88, + 0x88, 0x8e, 0x90, 0x85, 0x82, 0x89, 0x82, 0x79, 0x7c, 0x7d, 0x7b, + 0x74, 0x7d, 0x80, 0x7b, 0x7d, 0x85, 0x8c, 0x89, 0x93, 0x4b, 0x89, + 0x9f, 0x1d, 0x93, 0x71, 0x4f, 0x93, 0x49, 0x92, 0x98, 0x67, 0x9d, + 0xa5, 0x96, 0x91, 0x9c, 0x99, 0x91, 0x83, 0x72, 0x91, 0x6f, 0x5c, + 0x7d, 0x6c, 0x74, 0x6a, 0x7a, 0x8d, 0x7c, 0x81, 0x94, 0x98, 0x81, + 0x8c, 0x8e, 0x88, 0x7c, 0x73, 0x80, 0x73, 0x69, 0x6e, 0x79, 0x71, + 0x70, 0x80, 0x86, 0x83, 0x85, 0x93, 0x92, 0x88, 0x89, 0x8f, 0x85, + 0x79, 0x7f, 0x7f, 0x76, 0x74, 0x7a, 0x7f, 0x79, 0x7b, 0x88, 0x83, + 0x84, 0x84, 0x8e, 0x8b, 0x90, 0x78, 0x48, 0xa4, 0x60, 0x31, 0x98, + 0x50, 0x6e, 0x79, 0x62, 0xa5, 0x8b, 0x83, 0xa6, 0xad, 0x95, 0x91, + 0x9f, 0x8c, 0x84, 0x75, 0x6e, 0x82, 0x5f, 0x60, 0x79, 0x73, 0x73, + 0x79, 0x8d, 0x8e, 0x89, 0x8b, 0x9b, 0x92, 0x81, 0x88, 0x84, 0x7b, + 0x6e, 0x70, 0x73, 0x6c, 0x64, 0x75, 0x7e, 0x74, 0x82, 0x8d, 0x8e, + 0x8c, 0x8e, 0x93, 0x8e, 0x80, 0x83, 0x85, 0x75, 0x75, 0x7a, 0x79, + 0x76, 0x79, 0x81, 0x83, 0x7f, 0x86, 0x8b, 0x86, 0x85, 0x85, 0x8e, + 0x83, 0x84, 0x5b, 0x66, 0x91, 0x3a, 0x62, 0x7f, 0x5a, 0x7c, 0x74, + 0x89, 0x9c, 0x8f, 0x96, 0xaa, 0xa1, 0x8e, 0x94, 0x90, 0x7e, 0x77, + 0x6f, 0x6f, 0x71, 0x62, 0x6e, 0x7c, 0x79, 0x7b, 0x8b, 0x92, 0x8e, + 0x90, 0x8e, 0x96, 0x87, 0x7d, 0x82, 0x79, 0x70, 0x6d, 0x70, 0x6f, + 0x6c, 0x72, 0x7f, 0x7e, 0x80, 0x8d, 0x8f, 0x8d, 0x8d, 0x8d, 0x8b, + 0x82, 0x7d, 0x80, 0x79, 0x74, 0x78, 0x7a, 0x79, 0x7b, 0x81, 0x85, + 0x83, 0x86, 0x8b, 0x85, 0x86, 0x82, 0x86, 0x84, 0x83, 0x7a, 0x46, + 0x83, 0x79, 0x3a, 0x7c, 0x75, 0x6b, 0x7b, 0x81, 0x90, 0x9b, 0x93, + 0x92, 0xab, 0x97, 0x87, 0x91, 0x89, 0x77, 0x77, 0x70, 0x71, 0x73, + 0x68, 0x74, 0x81, 0x7b, 0x80, 0x90, 0x8c, 0x8b, 0x90, 0x8e, 0x8a, + 0x83, 0x7f, 0x7d, 0x78, 0x70, 0x71, 0x70, 0x70, 0x72, 0x76, 0x7f, + 0x82, 0x85, 0x8b, 0x8e, 0x8c, 0x8b, 0x89, 0x87, 0x82, 0x7d, 0x7c, + 0x7a, 0x78, 0x78, 0x7b, 0x7b, 0x7d, 0x81, 0x82, 0x84, 0x86, 0x85, + 0x85, 0x86, 0x83, 0x89, 0x81, 0x88, 0x68, 0x56, 0x90, 0x5f, 0x4d, + 0x7d, 0x74, 0x6b, 0x79, 0x8b, 0x89, 0x99, 0x92, 0x95, 0xa7, 0x95, + 0x89, 0x91, 0x8c, 0x78, 0x7a, 0x76, 0x71, 0x72, 0x6e, 0x70, 0x7c, + 0x7c, 0x7a, 0x89, 0x8a, 0x88, 0x8e, 0x8e, 0x89, 0x89, 0x84, 0x7f, + 0x7e, 0x75, 0x72, 0x75, 0x72, 0x6f, 0x77, 0x7c, 0x7b, 0x83, 0x87, + 0x88, 0x8a, 0x89, 0x88, 0x87, 0x84, 0x7f, 0x7f, 0x7e, 0x7a, 0x7b, + 0x7c, 0x7b, 0x7e, 0x7e, 0x7d, 0x82, 0x82, 0x80, 0x83, 0x83, 0x82, + 0x88, 0x84, 0x89, 0x74, 0x5f, 0x8b, 0x75, 0x56, 0x73, 0x7e, 0x6e, + 0x6e, 0x86, 0x82, 0x8a, 0x91, 0x8b, 0x97, 0x9a, 0x8f, 0x89, 0x92, + 0x8a, 0x7f, 0x7d, 0x7d, 0x79, 0x74, 0x74, 0x75, 0x78, 0x78, 0x7a, + 0x7e, 0x82, 0x84, 0x86, 0x88, 0x87, 0x87, 0x85, 0x83, 0x80, 0x7d, + 0x7b, 0x79, 0x78, 0x78, 0x79, 0x7b, 0x7e, 0x7e, 0x80, 0x81, 0x83, + 0x83, 0x82, 0x83, 0x82, 0x81, 0x82, 0x81, 0x80, 0x7e, 0x7e, 0x7f, + 0x7d, 0x7d, 0x7f, 0x7e, 0x7e, 0x80, 0x81, 0x82, 0x84, 0x85, 0x84, + 0x8a, 0x71, 0x6d, 0x8b, 0x76, 0x65, 0x73, 0x7f, 0x75, 0x6e, 0x7f, + 0x81, 0x83, 0x88, 0x89, 0x8a, 0x93, 0x91, 0x84, 0x8a, 0x8f, 0x84, + 0x7c, 0x81, 0x80, 0x7a, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7c, 0x7e, + 0x84, 0x81, 0x7e, 0x82, 0x84, 0x7f, 0x7d, 0x80, 0x7d, 0x7b, 0x7d, + 0x7c, 0x7b, 0x7e, 0x7e, 0x7d, 0x81, 0x81, 0x81, 0x81, 0x83, 0x83, + 0x80, 0x82, 0x81, 0x80, 0x80, 0x7e, 0x7e, 0x7e, 0x7d, 0x7e, 0x7f, + 0x7f, 0x7f, 0x81, 0x81, 0x81, 0x83, 0x81, 0x82, 0x84, 0x81, 0x84, + 0x72, 0x72, 0x88, 0x74, 0x6b, 0x79, 0x7f, 0x76, 0x75, 0x81, 0x7f, + 0x83, 0x86, 0x86, 0x87, 0x8c, 0x8d, 0x85, 0x85, 0x8a, 0x85, 0x7d, + 0x81, 0x82, 0x7e, 0x7e, 0x7f, 0x7e, 0x80, 0x81, 0x7e, 0x7f, 0x82, + 0x7f, 0x7d, 0x7d, 0x7f, 0x7c, 0x79, 0x7d, 0x7d, 0x7b, 0x7d, 0x7e, + 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x82, 0x83, 0x83, 0x81, 0x81, 0x80, + 0x80, 0x7f, 0x7e, 0x7f, 0x7e, 0x7e, 0x7e, 0x80, 0x80, 0x80, 0x81, + 0x81, 0x81, 0x82, 0x80, 0x82, 0x80, 0x7e, 0x80, 0x80, 0x80, 0x81, + 0x82, 0x72, 0x76, 0x88, 0x76, 0x70, 0x7b, 0x81, 0x78, 0x73, 0x81, + 0x7e, 0x7e, 0x84, 0x83, 0x84, 0x8b, 0x8a, 0x83, 0x87, 0x8b, 0x86, + 0x80, 0x83, 0x84, 0x81, 0x7e, 0x80, 0x81, 0x7e, 0x7e, 0x7c, 0x7d, + 0x80, 0x7d, 0x7a, 0x7e, 0x7e, 0x7c, 0x7c, 0x7e, 0x7e, 0x7c, 0x7e, + 0x80, 0x80, 0x7f, 0x81, 0x80, 0x80, 0x7f, 0x80, 0x81, 0x7f, 0x7f, + 0x80, 0x80, 0x81, 0x7f, 0x81, 0x81, 0x81, 0x82, 0x81, 0x82, 0x81, + 0x80, 0x81, 0x80, 0x7e, 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x80, 0x81, + 0x80, 0x83, 0x83, 0x85, 0x7a, 0x70, 0x8a, 0x7c, 0x68, 0x79, 0x7e, + 0x75, 0x6d, 0x7f, 0x7f, 0x7a, 0x85, 0x84, 0x88, 0x8f, 0x8c, 0x87, + 0x8d, 0x8e, 0x85, 0x82, 0x85, 0x82, 0x7a, 0x7c, 0x7e, 0x7a, 0x79, + 0x7c, 0x7b, 0x7c, 0x7f, 0x7e, 0x7f, 0x80, 0x81, 0x7f, 0x80, 0x81, + 0x7f, 0x7e, 0x80, 0x7d, 0x7d, 0x7e, 0x7b, 0x7f, 0x7d, 0x7d, 0x7f, + 0x7e, 0x7f, 0x80, 0x81, 0x81, 0x82, 0x83, 0x81, 0x82, 0x82, 0x81, + 0x80, 0x81, 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x81, + 0x80, 0x81, 0x81, 0x81, 0x81, 0x7f, 0x84, 0x81, 0x82, 0x72, 0x70, + 0x8e, 0x6c, 0x67, 0x83, 0x75, 0x70, 0x74, 0x80, 0x7b, 0x81, 0x85, + 0x82, 0x93, 0x8d, 0x86, 0x92, 0x92, 0x86, 0x89, 0x89, 0x83, 0x80, + 0x7d, 0x7b, 0x7d, 0x79, 0x74, 0x7c, 0x7b, 0x77, 0x7d, 0x80, 0x7d, + 0x7f, 0x83, 0x81, 0x84, 0x82, 0x7f, 0x84, 0x82, 0x7d, 0x80, 0x81, + 0x7b, 0x7b, 0x80, 0x7b, 0x79, 0x7d, 0x7c, 0x7c, 0x7b, 0x7f, 0x82, + 0x80, 0x80, 0x85, 0x86, 0x83, 0x86, 0x86, 0x86, 0x84, 0x83, 0x84, + 0x81, 0x7f, 0x7f, 0x7f, 0x7d, 0x7c, 0x7d, 0x7f, 0x7e, 0x7f, 0x81, + 0x87, 0x81, 0x86, 0x77, 0x6d, 0x91, 0x63, 0x6a, 0x82, 0x63, 0x77, + 0x6f, 0x74, 0x81, 0x7d, 0x7f, 0x8e, 0x92, 0x88, 0x97, 0x94, 0x92, + 0x93, 0x8a, 0x8c, 0x8a, 0x7d, 0x7e, 0x7e, 0x76, 0x74, 0x74, 0x75, + 0x74, 0x74, 0x78, 0x7e, 0x7b, 0x7f, 0x84, 0x84, 0x86, 0x85, 0x88, + 0x88, 0x84, 0x82, 0x85, 0x80, 0x7e, 0x7c, 0x79, 0x7c, 0x77, 0x77, + 0x7a, 0x78, 0x78, 0x7b, 0x7d, 0x7e, 0x80, 0x83, 0x86, 0x84, 0x86, + 0x8a, 0x88, 0x85, 0x86, 0x87, 0x84, 0x82, 0x83, 0x82, 0x7f, 0x7e, + 0x7f, 0x7e, 0x7e, 0x7d, 0x7f, 0x7f, 0x80, 0x82, 0x81, 0x83, 0x69, + 0x81, 0x7f, 0x5f, 0x7e, 0x6b, 0x72, 0x74, 0x6a, 0x81, 0x7c, 0x7a, + 0x89, 0x8c, 0x8a, 0x92, 0x8e, 0x96, 0x93, 0x89, 0x91, 0x8b, 0x84, + 0x84, 0x7e, 0x7f, 0x7a, 0x74, 0x7a, 0x77, 0x73, 0x78, 0x79, 0x7a, + 0x7a, 0x7c, 0x81, 0x80, 0x80, 0x85, 0x85, 0x85, 0x85, 0x84, 0x87, + 0x83, 0x82, 0x84, 0x81, 0x7e, 0x7b, 0x7c, 0x7b, 0x76, 0x78, 0x79, + 0x78, 0x77, 0x7b, 0x7e, 0x7d, 0x80, 0x85, 0x85, 0x85, 0x87, 0x89, + 0x88, 0x87, 0x88, 0x87, 0x83, 0x83, 0x82, 0x80, 0x7e, 0x7e, 0x7e, + 0x7c, 0x7c, 0x7c, 0x7d, 0x7d, 0x80, 0x7e, 0x83, 0x76, 0x75, 0x85, + 0x6e, 0x77, 0x78, 0x72, 0x79, 0x70, 0x79, 0x7f, 0x78, 0x81, 0x85, + 0x84, 0x8b, 0x87, 0x8e, 0x8e, 0x88, 0x8e, 0x8c, 0x88, 0x88, 0x84, + 0x84, 0x82, 0x7d, 0x7f, 0x7d, 0x7a, 0x7a, 0x79, 0x7a, 0x79, 0x7a, + 0x7c, 0x7c, 0x7c, 0x7e, 0x7f, 0x80, 0x80, 0x81, 0x83, 0x82, 0x82, + 0x83, 0x83, 0x81, 0x80, 0x81, 0x7f, 0x7d, 0x7d, 0x7d, 0x7c, 0x7b, + 0x7c, 0x7c, 0x7d, 0x7d, 0x7e, 0x80, 0x80, 0x81, 0x83, 0x82, 0x82, + 0x83, 0x84, 0x83, 0x82, 0x82, 0x82, 0x80, 0x80, 0x81, 0x80, 0x7f, + 0x7f, 0x7e, 0x7f, 0x7e, 0x7d, 0x7e, 0x7e, 0x7d, 0x7e, 0x7e, 0x7e, + 0x7e, 0x80, 0x7c, 0x7c, 0x80, 0x7b, 0x7c, 0x7d, 0x7c, 0x7d, 0x7c, + 0x7c, 0x7f, 0x7c, 0x7f, 0x81, 0x80, 0x83, 0x82, 0x83, 0x85, 0x83, + 0x85, 0x85, 0x83, 0x85, 0x83, 0x83, 0x84, 0x82, 0x83, 0x82, 0x81, + 0x80, 0x80, 0x7f, 0x7e, 0x7d, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, + 0x7d, 0x7e, 0x7e, 0x7f, 0x80, 0x80, 0x80, 0x81, 0x81, 0x80, 0x80, + 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x80, + 0x80, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x80, 0x80, + 0x7f, 0x7f, 0x7e, 0x7e, 0x7d, 0x7d, 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, + 0x7f, 0x7f, 0x80, 0x81, 0x80, 0x81, 0x81, 0x81, 0x81, 0x80, 0x81, + 0x80, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x7f, 0x7f, 0x80, 0x7f, 0x7e, 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, + 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x81, 0x80, 0x81, 0x81, 0x80, 0x80, + 0x80, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x80, + 0x80, 0x81, 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x7f, + 0x7e, 0x7f, 0x7e, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, + 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, + 0x80, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x81, 0x80, 0x80, 0x7f, + 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, + 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x80, + 0x80, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7e, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x81, + 0x80, 0x81, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x81, 0x80, 0x80, + 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x7f, 0x7f, 0x81, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x7e, 0x81, + 0x80, 0x7e, 0x81, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, + 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, + 0x80, 0x7e, 0x7f, 0x80, 0x7e, 0x7f, 0x80, 0x80, 0x7f, 0x81, 0x80, + 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7e, + 0x7f, 0x81, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, + 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x7f, + 0x80, 0x7e, 0x80, 0x7e, 0x80, 0x7e, 0x7f, 0x81, 0x7e, 0x80, 0x80, + 0x7f, 0x80, 0x80, 0x7f, 0x82, 0x7f, 0x7f, 0x82, 0x7f, 0x7f, 0x81, + 0x7f, 0x7e, 0x80, 0x7e, 0x80, 0x80, 0x7d, 0x81, 0x7f, 0x7f, 0x81, + 0x7f, 0x80, 0x81, 0x7e, 0x81, 0x80, 0x7e, 0x81, 0x7f, 0x7f, 0x81, + 0x7e, 0x80, 0x81, 0x7d, 0x82, 0x7f, 0x7f, 0x82, 0x7e, 0x81, 0x80, + 0x7d, 0x81, 0x7f, 0x7e, 0x81, 0x7e, 0x80, 0x7e, 0x7f, 0x80, 0x7e, + 0x80, 0x80, 0x7f, 0x81, 0x80, 0x7e, 0x82, 0x7f, 0x7e, 0x81, 0x7e, + 0x7e, 0x80, 0x7d, 0x80, 0x80, 0x7c, 0x83, 0x7e, 0x7f, 0x82, 0x7e, + 0x82, 0x80, 0x7f, 0x82, 0x7f, 0x7f, 0x81, 0x7e, 0x80, 0x80, 0x7d, + 0x82, 0x7d, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x81, 0x7f, 0x7f, 0x7f, + 0x80, 0x7f, 0x80, 0x7e, 0x80, 0x7f, 0x7e, 0x82, 0x7e, 0x7f, 0x82, + 0x7e, 0x81, 0x80, 0x7e, 0x81, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, + 0x7f, 0x7f, 0x80, 0x7e, 0x7f, 0x81, 0x7e, 0x81, 0x80, 0x7f, 0x81, + 0x7f, 0x80, 0x80, 0x80, 0x80, 0x7e, 0x81, 0x7f, 0x7f, 0x80, 0x7f, + 0x80, 0x7e, 0x80, 0x7f, 0x7f, 0x81, 0x7e, 0x80, 0x81, 0x7d, 0x82, + 0x80, 0x7e, 0x82, 0x7d, 0x81, 0x80, 0x7d, 0x83, 0x7e, 0x7e, 0x82, + 0x7d, 0x81, 0x7f, 0x7f, 0x82, 0x7e, 0x81, 0x80, 0x7f, 0x81, 0x80, + 0x7f, 0x82, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x7e, 0x80, 0x7f, + 0x7e, 0x81, 0x7f, 0x7e, 0x81, 0x7f, 0x7f, 0x81, 0x7e, 0x80, 0x81, + 0x7e, 0x81, 0x7f, 0x80, 0x80, 0x7e, 0x82, 0x7e, 0x7f, 0x81, 0x7c, + 0x81, 0x7f, 0x7d, 0x82, 0x7d, 0x7f, 0x82, 0x7c, 0x82, 0x81, 0x7d, + 0x83, 0x80, 0x7d, 0x82, 0x7f, 0x7e, 0x82, 0x7d, 0x7f, 0x82, 0x7c, + 0x81, 0x81, 0x7d, 0x81, 0x7e, 0x7f, 0x81, 0x7d, 0x81, 0x81, 0x7e, + 0x7f, 0x81, 0x81, 0x7e, 0x81, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x80, + 0x7e, 0x7f, 0x80, 0x7e, 0x80, 0x7e, 0x81, 0x80, 0x7e, 0x81, 0x80, + 0x80, 0x80, 0x80, 0x81, 0x80, 0x7e, 0x80, 0x80, 0x7e, 0x7f, 0x7e, + 0x80, 0x80, 0x7d, 0x81, 0x81, 0x7d, 0x81, 0x81, 0x7f, 0x81, 0x7f, + 0x80, 0x80, 0x7e, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x7f, 0x80, 0x80, 0x7e, 0x82, 0x7f, 0x7e, 0x82, 0x7e, 0x7e, 0x81, + 0x7e, 0x80, 0x80, 0x7c, 0x82, 0x7f, 0x7c, 0x82, 0x7f, 0x7f, 0x80, + 0x7f, 0x81, 0x80, 0x7e, 0x81, 0x81, 0x7e, 0x80, 0x80, 0x7f, 0x7f, + 0x7f, 0x7f, 0x81, 0x7f, 0x7f, 0x82, 0x7f, 0x7f, 0x80, 0x80, 0x80, + 0x80, 0x7e, 0x81, 0x7f, 0x7e, 0x80, 0x7f, 0x80, 0x7f, 0x7e, 0x81, + 0x7f, 0x7d, 0x82, 0x7f, 0x7f, 0x81, 0x7d, 0x82, 0x7f, 0x7e, 0x81, + 0x80, 0x7e, 0x7f, 0x80, 0x7f, 0x7f, 0x7e, 0x80, 0x80, 0x7f, 0x7f, + 0x80, 0x80, 0x7f, 0x80, 0x81, 0x81, 0x7e, 0x80, 0x7f, 0x7f, 0x80, + 0x7e, 0x7f, 0x80, 0x7e, 0x80, 0x81, 0x7f, 0x81, 0x80, 0x7f, 0x80, + 0x7f, 0x7e, 0x80, 0x7f, 0x7f, 0x80, 0x7e, 0x80, 0x80, 0x7f, 0x80, + 0x80, 0x80, 0x81, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x80, + 0x7f, 0x7e, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, + 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + }, + }, + "zh": [][]byte{ + { // 0 + 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, + 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, + 0x80, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, + 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, + 0x80, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, + 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x80, + 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, + 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, + 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x80, + 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x80, + 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x81, + 0x7f, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x81, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, + 0x7e, 0x7e, 0x7e, 0x7d, 0x7e, 0x7d, 0x7e, 0x7e, 0x7e, 0x7f, 0x80, + 0x80, 0x80, 0x82, 0x81, 0x82, 0x82, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x81, 0x81, 0x7f, 0x80, 0x7e, 0x7d, 0x7d, 0x7a, + 0x7a, 0x78, 0x78, 0x77, 0x76, 0x76, 0x77, 0x78, 0x78, 0x7a, 0x7b, + 0x7f, 0x82, 0x83, 0x88, 0x8a, 0x8c, 0x90, 0x8f, 0x94, 0x92, 0x93, + 0x93, 0x90, 0x90, 0x8b, 0x88, 0x84, 0x81, 0x7d, 0x77, 0x73, 0x6e, + 0x69, 0x65, 0x65, 0x61, 0x64, 0x61, 0x66, 0x65, 0x6a, 0x69, 0x71, + 0x73, 0x7b, 0x87, 0x86, 0x97, 0x92, 0xa5, 0x9f, 0xa5, 0xab, 0xa3, + 0xab, 0x9f, 0xa0, 0x98, 0x90, 0x8b, 0x83, 0x7d, 0x76, 0x70, 0x6d, + 0x68, 0x64, 0x62, 0x60, 0x5f, 0x60, 0x5e, 0x5e, 0x60, 0x60, 0x64, + 0x64, 0x70, 0x76, 0x7c, 0x87, 0x8b, 0x99, 0x9a, 0xa5, 0xa9, 0xaa, + 0xae, 0xaa, 0xaa, 0xa2, 0x9e, 0x97, 0x8f, 0x89, 0x81, 0x7d, 0x77, + 0x74, 0x6f, 0x6d, 0x69, 0x66, 0x65, 0x62, 0x61, 0x60, 0x5f, 0x5d, + 0x60, 0x60, 0x64, 0x67, 0x71, 0x74, 0x7f, 0x85, 0x8e, 0x98, 0x9a, + 0xa7, 0xa6, 0xac, 0xab, 0xaa, 0xa9, 0xa3, 0x9f, 0x99, 0x93, 0x8b, + 0x84, 0x7d, 0x77, 0x71, 0x6c, 0x6a, 0x63, 0x63, 0x60, 0x5f, 0x60, + 0x5e, 0x61, 0x60, 0x63, 0x65, 0x69, 0x6e, 0x72, 0x77, 0x7e, 0x83, + 0x8c, 0x91, 0x98, 0x9c, 0xa2, 0xa4, 0xa7, 0xa5, 0xa5, 0xa2, 0xa2, + 0x9d, 0x95, 0x96, 0x88, 0x85, 0x7f, 0x7a, 0x73, 0x73, 0x6d, 0x6a, + 0x66, 0x61, 0x62, 0x5f, 0x61, 0x5f, 0x5f, 0x5f, 0x5e, 0x5c, 0x63, + 0x6b, 0x70, 0x78, 0x83, 0x8a, 0x95, 0x9b, 0xa6, 0xaa, 0xad, 0xb2, + 0xad, 0xad, 0xa6, 0xa0, 0x9b, 0x91, 0x8e, 0x83, 0x7e, 0x79, 0x73, + 0x72, 0x6c, 0x6f, 0x6a, 0x6b, 0x6b, 0x67, 0x63, 0x62, 0x5f, 0x5e, + 0x59, 0x5b, 0x58, 0x54, 0x5b, 0x62, 0x71, 0x79, 0x8d, 0x99, 0xa1, + 0xad, 0xb5, 0xb6, 0xbc, 0xb8, 0xb3, 0xaf, 0xa7, 0x9e, 0x95, 0x8f, + 0x84, 0x7e, 0x77, 0x73, 0x6f, 0x6d, 0x6d, 0x6c, 0x6e, 0x6e, 0x6e, + 0x6e, 0x69, 0x66, 0x63, 0x5d, 0x5e, 0x57, 0x57, 0x51, 0x53, 0x57, + 0x5d, 0x73, 0x76, 0x8e, 0x99, 0xa4, 0xaf, 0xb6, 0xbc, 0xba, 0xbe, + 0xb5, 0xaf, 0xab, 0x9c, 0x95, 0x8f, 0x82, 0x7f, 0x76, 0x72, 0x70, + 0x6b, 0x6e, 0x6c, 0x6e, 0x6f, 0x6f, 0x73, 0x6e, 0x6e, 0x69, 0x66, + 0x62, 0x5d, 0x5e, 0x55, 0x5a, 0x51, 0x5a, 0x5c, 0x67, 0x77, 0x7f, + 0x97, 0x9a, 0xab, 0xb1, 0xb8, 0xbb, 0xba, 0xbb, 0xb4, 0xad, 0xa7, + 0x9c, 0x94, 0x8c, 0x83, 0x7d, 0x77, 0x72, 0x6f, 0x6c, 0x6d, 0x6b, + 0x6d, 0x6f, 0x6e, 0x70, 0x6e, 0x6f, 0x6b, 0x6b, 0x65, 0x65, 0x5f, + 0x5d, 0x5c, 0x56, 0x59, 0x5a, 0x5d, 0x6c, 0x74, 0x81, 0x94, 0x98, + 0xaa, 0xad, 0xb7, 0xbb, 0xbb, 0xbd, 0xb5, 0xb2, 0xa8, 0xa2, 0x98, + 0x8f, 0x88, 0x7b, 0x7a, 0x72, 0x6d, 0x6d, 0x69, 0x6b, 0x6a, 0x6d, + 0x6e, 0x6f, 0x71, 0x70, 0x70, 0x6d, 0x6b, 0x68, 0x66, 0x62, 0x61, + 0x5e, 0x5d, 0x5e, 0x5d, 0x63, 0x69, 0x75, 0x7b, 0x8e, 0x93, 0x9e, + 0xaa, 0xac, 0xb7, 0xb6, 0xb9, 0xb7, 0xb1, 0xad, 0xa4, 0x9b, 0x94, + 0x87, 0x82, 0x79, 0x73, 0x70, 0x6b, 0x6d, 0x69, 0x6b, 0x6f, 0x6d, + 0x73, 0x71, 0x72, 0x72, 0x70, 0x6e, 0x6c, 0x68, 0x64, 0x63, 0x5f, + 0x60, 0x5d, 0x5f, 0x62, 0x64, 0x6e, 0x78, 0x7f, 0x90, 0x95, 0x9f, + 0xa9, 0xac, 0xb3, 0xb6, 0xb6, 0xb5, 0xb1, 0xaa, 0xa5, 0x99, 0x92, + 0x89, 0x80, 0x7a, 0x73, 0x6f, 0x6c, 0x6b, 0x6b, 0x6c, 0x6e, 0x6e, + 0x72, 0x73, 0x71, 0x75, 0x70, 0x70, 0x6d, 0x69, 0x69, 0x64, 0x65, + 0x62, 0x64, 0x64, 0x65, 0x69, 0x6c, 0x72, 0x7d, 0x80, 0x8f, 0x95, + 0x9a, 0xa7, 0xa5, 0xaf, 0xb0, 0xb0, 0xb0, 0xab, 0xa6, 0xa2, 0x97, + 0x92, 0x88, 0x7f, 0x7a, 0x73, 0x70, 0x6e, 0x6c, 0x6e, 0x6d, 0x6f, + 0x72, 0x71, 0x76, 0x73, 0x76, 0x74, 0x72, 0x72, 0x6d, 0x6c, 0x69, + 0x66, 0x67, 0x66, 0x69, 0x6a, 0x6b, 0x6e, 0x73, 0x74, 0x7e, 0x84, + 0x87, 0x96, 0x94, 0x9e, 0xa2, 0xa3, 0xab, 0xa8, 0xab, 0xa8, 0xa4, + 0x9f, 0x99, 0x91, 0x8b, 0x83, 0x7b, 0x76, 0x72, 0x6f, 0x6e, 0x6e, + 0x6f, 0x6f, 0x71, 0x73, 0x75, 0x76, 0x76, 0x77, 0x75, 0x74, 0x73, + 0x70, 0x70, 0x6d, 0x6c, 0x6b, 0x6b, 0x6e, 0x6e, 0x70, 0x72, 0x75, + 0x77, 0x7c, 0x82, 0x86, 0x8d, 0x93, 0x94, 0x9e, 0x9d, 0xa2, 0xa6, + 0xa1, 0xa7, 0x9e, 0x9e, 0x99, 0x90, 0x8d, 0x84, 0x7e, 0x79, 0x76, + 0x71, 0x72, 0x6f, 0x71, 0x72, 0x72, 0x76, 0x75, 0x78, 0x76, 0x77, + 0x77, 0x76, 0x76, 0x74, 0x73, 0x72, 0x71, 0x71, 0x70, 0x72, 0x72, + 0x74, 0x76, 0x77, 0x79, 0x79, 0x7d, 0x7b, 0x81, 0x82, 0x88, 0x8c, + 0x8f, 0x95, 0x96, 0x9b, 0x9d, 0x9e, 0x9f, 0x9d, 0x9b, 0x97, 0x93, + 0x8d, 0x87, 0x82, 0x7d, 0x79, 0x76, 0x74, 0x73, 0x73, 0x73, 0x74, + 0x75, 0x77, 0x77, 0x78, 0x78, 0x77, 0x77, 0x75, 0x74, 0x74, 0x73, + 0x73, 0x73, 0x73, 0x74, 0x73, 0x76, 0x75, 0x78, 0x78, 0x7a, 0x78, + 0x7e, 0x79, 0x81, 0x82, 0x84, 0x8f, 0x89, 0x98, 0x93, 0x9a, 0x9d, + 0x9b, 0xa1, 0x9a, 0x9c, 0x97, 0x90, 0x8f, 0x86, 0x82, 0x7f, 0x78, + 0x78, 0x74, 0x73, 0x75, 0x73, 0x76, 0x76, 0x77, 0x79, 0x77, 0x7a, + 0x77, 0x78, 0x77, 0x75, 0x77, 0x74, 0x75, 0x75, 0x75, 0x77, 0x75, + 0x77, 0x78, 0x79, 0x7a, 0x7a, 0x7b, 0x78, 0x7d, 0x76, 0x81, 0x7d, + 0x84, 0x8a, 0x87, 0x96, 0x8e, 0x9b, 0x99, 0x9b, 0x9f, 0x9a, 0x9b, + 0x96, 0x91, 0x8d, 0x87, 0x82, 0x7f, 0x79, 0x79, 0x75, 0x74, 0x75, + 0x75, 0x75, 0x79, 0x75, 0x7a, 0x78, 0x78, 0x7a, 0x77, 0x7a, 0x78, + 0x78, 0x78, 0x76, 0x77, 0x76, 0x75, 0x76, 0x75, 0x77, 0x76, 0x78, + 0x78, 0x78, 0x78, 0x7b, 0x78, 0x81, 0x7e, 0x84, 0x8b, 0x88, 0x95, + 0x92, 0x99, 0x9b, 0x9a, 0x9e, 0x9b, 0x98, 0x97, 0x8f, 0x8e, 0x88, + 0x83, 0x82, 0x7b, 0x7b, 0x78, 0x77, 0x77, 0x76, 0x77, 0x76, 0x78, + 0x76, 0x78, 0x78, 0x77, 0x79, 0x76, 0x79, 0x77, 0x78, 0x78, 0x77, + 0x78, 0x77, 0x78, 0x78, 0x78, 0x79, 0x79, 0x79, 0x79, 0x7c, 0x7a, + 0x81, 0x80, 0x86, 0x8b, 0x8a, 0x94, 0x93, 0x97, 0x9a, 0x99, 0x9b, + 0x99, 0x95, 0x94, 0x8e, 0x8b, 0x87, 0x82, 0x81, 0x7c, 0x7b, 0x7a, + 0x77, 0x77, 0x75, 0x74, 0x74, 0x73, 0x75, 0x73, 0x77, 0x76, 0x75, + 0x7a, 0x76, 0x7b, 0x7b, 0x7b, 0x7f, 0x7a, 0x7f, 0x7b, 0x7c, 0x7d, + 0x7b, 0x7d, 0x7c, 0x7d, 0x7f, 0x84, 0x83, 0x8c, 0x8b, 0x90, 0x94, + 0x92, 0x99, 0x94, 0x97, 0x95, 0x91, 0x92, 0x8a, 0x8a, 0x85, 0x81, + 0x80, 0x7b, 0x7a, 0x77, 0x76, 0x76, 0x75, 0x75, 0x76, 0x73, 0x76, + 0x74, 0x75, 0x78, 0x76, 0x79, 0x79, 0x79, 0x7c, 0x7b, 0x7c, 0x7e, + 0x7d, 0x7f, 0x7d, 0x7f, 0x7f, 0x7f, 0x82, 0x82, 0x86, 0x87, 0x8c, + 0x8c, 0x90, 0x92, 0x91, 0x97, 0x91, 0x95, 0x91, 0x8e, 0x8d, 0x88, + 0x87, 0x82, 0x81, 0x7d, 0x7b, 0x7a, 0x77, 0x77, 0x75, 0x76, 0x75, + 0x76, 0x76, 0x76, 0x77, 0x77, 0x77, 0x78, 0x7a, 0x78, 0x7c, 0x79, + 0x7b, 0x7b, 0x7a, 0x7d, 0x7a, 0x7f, 0x7d, 0x7e, 0x80, 0x7e, 0x82, + 0x85, 0x85, 0x8d, 0x8c, 0x8f, 0x95, 0x90, 0x97, 0x94, 0x93, 0x93, + 0x8f, 0x8d, 0x8a, 0x87, 0x84, 0x80, 0x7d, 0x7a, 0x79, 0x76, 0x76, + 0x75, 0x74, 0x74, 0x72, 0x74, 0x73, 0x75, 0x76, 0x75, 0x78, 0x77, + 0x7a, 0x79, 0x7a, 0x7a, 0x7a, 0x7b, 0x7d, 0x7e, 0x7f, 0x80, 0x7b, + 0x7f, 0x7b, 0x80, 0x83, 0x84, 0x8c, 0x8b, 0x8f, 0x93, 0x94, 0x98, + 0x97, 0x96, 0x96, 0x93, 0x8f, 0x8e, 0x88, 0x85, 0x80, 0x7d, 0x7b, + 0x78, 0x76, 0x75, 0x74, 0x74, 0x74, 0x73, 0x75, 0x72, 0x74, 0x73, + 0x73, 0x75, 0x74, 0x75, 0x75, 0x77, 0x75, 0x78, 0x78, 0x78, 0x7a, + 0x78, 0x7a, 0x7a, 0x7d, 0x7c, 0x84, 0x85, 0x8b, 0x94, 0x93, 0x9c, + 0x9b, 0x9d, 0x9e, 0x9c, 0x9b, 0x98, 0x95, 0x8f, 0x8d, 0x88, 0x83, + 0x81, 0x7d, 0x7a, 0x79, 0x76, 0x74, 0x74, 0x71, 0x71, 0x6f, 0x6f, + 0x6e, 0x6c, 0x6d, 0x6c, 0x6d, 0x6e, 0x6f, 0x71, 0x72, 0x74, 0x74, + 0x76, 0x76, 0x79, 0x7a, 0x7a, 0x7d, 0x7c, 0x84, 0x88, 0x91, 0x97, + 0x9b, 0xa0, 0xa0, 0xa3, 0xa3, 0xa3, 0xa1, 0x9c, 0x99, 0x93, 0x8f, + 0x8a, 0x86, 0x82, 0x7e, 0x7d, 0x7a, 0x79, 0x76, 0x74, 0x73, 0x6f, + 0x6f, 0x6c, 0x6b, 0x6b, 0x6a, 0x6b, 0x6a, 0x6b, 0x6b, 0x6e, 0x6f, + 0x72, 0x74, 0x75, 0x77, 0x77, 0x78, 0x78, 0x79, 0x79, 0x7c, 0x82, + 0x87, 0x8f, 0x96, 0x9a, 0xa0, 0xa1, 0xa4, 0xa4, 0xa5, 0xa2, 0xa0, + 0x9b, 0x96, 0x91, 0x8c, 0x88, 0x83, 0x80, 0x7c, 0x7b, 0x79, 0x78, + 0x76, 0x73, 0x71, 0x6f, 0x6e, 0x6c, 0x6b, 0x6b, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6c, 0x6e, 0x70, 0x73, 0x74, 0x76, 0x76, 0x79, 0x79, 0x7a, + 0x7a, 0x79, 0x7b, 0x7f, 0x86, 0x8d, 0x95, 0x98, 0x9d, 0x9f, 0xa2, + 0xa3, 0xa5, 0xa2, 0xa0, 0x9d, 0x98, 0x94, 0x8f, 0x8a, 0x86, 0x82, + 0x7e, 0x7c, 0x7a, 0x78, 0x76, 0x75, 0x72, 0x71, 0x6e, 0x6c, 0x6c, + 0x6a, 0x6b, 0x6a, 0x6a, 0x6b, 0x6b, 0x6d, 0x6f, 0x71, 0x73, 0x74, + 0x76, 0x78, 0x79, 0x7a, 0x7a, 0x7a, 0x7b, 0x7c, 0x80, 0x85, 0x8b, + 0x91, 0x96, 0x9a, 0x9d, 0x9f, 0xa1, 0xa1, 0xa0, 0x9e, 0x9b, 0x97, + 0x94, 0x90, 0x8b, 0x87, 0x83, 0x80, 0x7e, 0x7b, 0x7a, 0x79, 0x77, + 0x75, 0x73, 0x70, 0x6e, 0x6c, 0x6b, 0x6a, 0x6a, 0x6a, 0x6a, 0x6b, + 0x6b, 0x6d, 0x6f, 0x71, 0x73, 0x75, 0x77, 0x78, 0x79, 0x7a, 0x7b, + 0x7b, 0x7c, 0x7d, 0x7f, 0x83, 0x88, 0x8e, 0x93, 0x96, 0x99, 0x9c, + 0x9e, 0xa0, 0xa0, 0x9f, 0x9d, 0x9a, 0x97, 0x94, 0x8f, 0x8b, 0x87, + 0x84, 0x80, 0x7e, 0x7c, 0x7a, 0x78, 0x76, 0x74, 0x72, 0x70, 0x6e, + 0x6c, 0x6b, 0x6b, 0x6b, 0x6a, 0x6a, 0x6b, 0x6b, 0x6d, 0x6f, 0x70, + 0x72, 0x74, 0x75, 0x77, 0x78, 0x79, 0x7a, 0x7a, 0x7b, 0x7b, 0x7c, + 0x7f, 0x84, 0x89, 0x8f, 0x92, 0x96, 0x98, 0x9c, 0x9e, 0xa0, 0xa0, + 0x9f, 0x9d, 0x9a, 0x97, 0x93, 0x90, 0x8b, 0x88, 0x83, 0x81, 0x7e, + 0x7c, 0x7a, 0x78, 0x76, 0x74, 0x73, 0x70, 0x6e, 0x6c, 0x6b, 0x6a, + 0x6a, 0x69, 0x69, 0x69, 0x6a, 0x6b, 0x6d, 0x6e, 0x71, 0x73, 0x74, + 0x76, 0x77, 0x79, 0x7a, 0x7b, 0x7b, 0x7b, 0x7c, 0x80, 0x85, 0x8a, + 0x90, 0x93, 0x96, 0x9a, 0x9d, 0xa0, 0xa2, 0xa2, 0x9f, 0x9e, 0x9b, + 0x98, 0x94, 0x90, 0x8b, 0x87, 0x83, 0x80, 0x7e, 0x7b, 0x79, 0x76, + 0x75, 0x73, 0x71, 0x6e, 0x6d, 0x6a, 0x6a, 0x6a, 0x69, 0x68, 0x68, + 0x69, 0x6a, 0x6c, 0x6d, 0x6e, 0x70, 0x73, 0x75, 0x77, 0x77, 0x79, + 0x7a, 0x7c, 0x7c, 0x7d, 0x7d, 0x80, 0x85, 0x8b, 0x91, 0x94, 0x97, + 0x9a, 0x9e, 0xa1, 0xa2, 0xa2, 0xa0, 0x9d, 0x9b, 0x98, 0x94, 0x8f, + 0x8b, 0x87, 0x83, 0x80, 0x7d, 0x7a, 0x78, 0x76, 0x75, 0x72, 0x70, + 0x6d, 0x6b, 0x6a, 0x69, 0x69, 0x67, 0x67, 0x67, 0x68, 0x69, 0x6b, + 0x6c, 0x6e, 0x71, 0x73, 0x75, 0x77, 0x79, 0x7b, 0x7b, 0x7c, 0x7c, + 0x7d, 0x81, 0x86, 0x8c, 0x91, 0x95, 0x98, 0x9c, 0x9f, 0xa2, 0xa3, + 0xa2, 0xa0, 0x9e, 0x9b, 0x98, 0x94, 0x90, 0x8a, 0x87, 0x83, 0x80, + 0x7d, 0x7a, 0x78, 0x75, 0x74, 0x72, 0x6f, 0x6d, 0x6c, 0x6b, 0x69, + 0x68, 0x67, 0x66, 0x66, 0x68, 0x69, 0x6a, 0x6c, 0x6f, 0x71, 0x74, + 0x75, 0x77, 0x79, 0x7b, 0x7b, 0x7b, 0x7c, 0x7e, 0x84, 0x88, 0x90, + 0x93, 0x97, 0x9a, 0x9e, 0xa1, 0xa3, 0xa4, 0xa1, 0xa0, 0x9c, 0x9a, + 0x95, 0x92, 0x8d, 0x89, 0x84, 0x82, 0x7e, 0x7b, 0x79, 0x77, 0x74, + 0x72, 0x70, 0x6e, 0x6c, 0x6b, 0x69, 0x67, 0x66, 0x65, 0x65, 0x67, + 0x68, 0x69, 0x6b, 0x6e, 0x70, 0x73, 0x75, 0x77, 0x79, 0x7a, 0x7b, + 0x7c, 0x7c, 0x7e, 0x84, 0x88, 0x90, 0x93, 0x98, 0x9a, 0x9f, 0xa1, + 0xa3, 0xa5, 0xa2, 0xa1, 0x9d, 0x9a, 0x96, 0x92, 0x8d, 0x89, 0x84, + 0x81, 0x7e, 0x7c, 0x79, 0x76, 0x74, 0x71, 0x6f, 0x6d, 0x6c, 0x69, + 0x68, 0x66, 0x65, 0x65, 0x65, 0x65, 0x67, 0x69, 0x6b, 0x6e, 0x71, + 0x73, 0x76, 0x77, 0x79, 0x7a, 0x7b, 0x7d, 0x7f, 0x84, 0x88, 0x90, + 0x94, 0x99, 0x9b, 0x9f, 0xa2, 0xa4, 0xa5, 0xa3, 0xa1, 0x9e, 0x9c, + 0x96, 0x93, 0x8d, 0x8a, 0x85, 0x82, 0x7e, 0x7c, 0x79, 0x76, 0x74, + 0x72, 0x70, 0x6d, 0x6b, 0x67, 0x67, 0x64, 0x65, 0x63, 0x64, 0x63, + 0x65, 0x68, 0x6b, 0x6d, 0x70, 0x73, 0x75, 0x77, 0x79, 0x79, 0x7c, + 0x7e, 0x82, 0x88, 0x8d, 0x93, 0x97, 0x9c, 0x9e, 0xa3, 0xa4, 0xa6, + 0xa4, 0xa3, 0x9f, 0x9d, 0x98, 0x94, 0x8f, 0x8a, 0x86, 0x82, 0x80, + 0x7c, 0x7b, 0x78, 0x77, 0x74, 0x72, 0x6f, 0x6c, 0x69, 0x67, 0x65, + 0x64, 0x63, 0x63, 0x63, 0x64, 0x66, 0x69, 0x6d, 0x70, 0x72, 0x74, + 0x76, 0x78, 0x7a, 0x7d, 0x7f, 0x84, 0x89, 0x90, 0x95, 0x99, 0x9e, + 0xa0, 0xa4, 0xa4, 0xa6, 0xa3, 0xa2, 0x9e, 0x9a, 0x96, 0x92, 0x8e, + 0x88, 0x86, 0x81, 0x7f, 0x7b, 0x7a, 0x77, 0x76, 0x73, 0x71, 0x6d, + 0x6b, 0x68, 0x67, 0x65, 0x64, 0x64, 0x63, 0x64, 0x66, 0x69, 0x6b, + 0x6f, 0x70, 0x73, 0x74, 0x77, 0x78, 0x7b, 0x7d, 0x83, 0x87, 0x8e, + 0x93, 0x98, 0x9c, 0x9f, 0xa2, 0xa4, 0xa5, 0xa3, 0xa2, 0x9e, 0x9c, + 0x96, 0x93, 0x8e, 0x8a, 0x86, 0x83, 0x80, 0x7d, 0x7b, 0x78, 0x77, + 0x74, 0x71, 0x6e, 0x6c, 0x6a, 0x68, 0x66, 0x66, 0x64, 0x64, 0x65, + 0x67, 0x68, 0x6b, 0x6e, 0x70, 0x72, 0x74, 0x75, 0x78, 0x7a, 0x7e, + 0x84, 0x8a, 0x8f, 0x93, 0x98, 0x9b, 0xa0, 0xa2, 0xa4, 0xa3, 0xa2, + 0xa0, 0x9d, 0x99, 0x95, 0x91, 0x8c, 0x89, 0x85, 0x82, 0x7f, 0x7d, + 0x7a, 0x78, 0x76, 0x73, 0x70, 0x6e, 0x6c, 0x6a, 0x69, 0x67, 0x67, + 0x67, 0x67, 0x68, 0x6a, 0x6c, 0x6e, 0x70, 0x72, 0x73, 0x75, 0x77, + 0x7a, 0x7c, 0x80, 0x86, 0x8c, 0x8f, 0x95, 0x98, 0x9b, 0x9f, 0xa0, + 0xa1, 0xa0, 0x9f, 0x9c, 0x9a, 0x96, 0x93, 0x8f, 0x8b, 0x87, 0x83, + 0x80, 0x7e, 0x7b, 0x78, 0x75, 0x73, 0x71, 0x6e, 0x6c, 0x6b, 0x6a, + 0x69, 0x6a, 0x69, 0x6a, 0x6a, 0x6d, 0x6e, 0x70, 0x72, 0x73, 0x75, + 0x77, 0x79, 0x7b, 0x7e, 0x82, 0x88, 0x8d, 0x91, 0x95, 0x98, 0x9a, + 0x9d, 0x9e, 0x9d, 0x9b, 0x9a, 0x97, 0x94, 0x91, 0x8e, 0x8a, 0x87, + 0x84, 0x81, 0x7f, 0x7d, 0x7a, 0x78, 0x76, 0x74, 0x72, 0x70, 0x6f, + 0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x73, 0x74, + 0x75, 0x77, 0x78, 0x7b, 0x7c, 0x81, 0x84, 0x89, 0x8d, 0x91, 0x94, + 0x96, 0x98, 0x99, 0x9a, 0x99, 0x98, 0x95, 0x93, 0x90, 0x8d, 0x8a, + 0x88, 0x85, 0x82, 0x80, 0x7e, 0x7c, 0x7a, 0x78, 0x76, 0x74, 0x72, + 0x70, 0x6f, 0x6f, 0x6e, 0x6f, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, + 0x75, 0x76, 0x78, 0x78, 0x79, 0x7a, 0x7c, 0x80, 0x83, 0x87, 0x8b, + 0x8e, 0x91, 0x94, 0x96, 0x97, 0x97, 0x96, 0x95, 0x93, 0x91, 0x8e, + 0x8b, 0x88, 0x86, 0x83, 0x82, 0x80, 0x7e, 0x7d, 0x7b, 0x79, 0x77, + 0x75, 0x74, 0x73, 0x71, 0x71, 0x71, 0x71, 0x72, 0x74, 0x75, 0x78, + 0x7a, 0x7c, 0x7e, 0x7f, 0x81, 0x82, 0x83, 0x83, 0x82, 0x81, 0x80, + 0x7e, 0x7e, 0x7c, 0x7c, 0x7a, 0x7a, 0x7b, 0x7d, 0x80, 0x83, 0x86, + 0x87, 0x8a, 0x8c, 0x8e, 0x8f, 0x90, 0x8f, 0x8e, 0x8d, 0x8b, 0x89, + 0x86, 0x85, 0x82, 0x80, 0x7e, 0x7e, 0x7c, 0x7b, 0x79, 0x79, 0x76, + 0x76, 0x74, 0x73, 0x72, 0x72, 0x72, 0x73, 0x74, 0x75, 0x77, 0x79, + 0x7c, 0x7e, 0x81, 0x82, 0x85, 0x86, 0x88, 0x89, 0x8a, 0x89, 0x89, + 0x89, 0x87, 0x86, 0x84, 0x83, 0x81, 0x80, 0x7e, 0x7e, 0x7c, 0x7c, + 0x7b, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7b, 0x7b, 0x7c, 0x7c, 0x7d, + 0x7e, 0x7f, 0x7f, 0x81, 0x82, 0x84, 0x85, 0x86, 0x88, 0x89, 0x8b, + 0x8b, 0x8c, 0x8b, 0x8b, 0x89, 0x88, 0x86, 0x84, 0x82, 0x7f, 0x7d, + 0x7b, 0x7a, 0x78, 0x77, 0x76, 0x76, 0x75, 0x75, 0x75, 0x75, 0x75, + 0x75, 0x76, 0x76, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7c, 0x7d, 0x7f, + 0x82, 0x84, 0x86, 0x89, 0x8b, 0x8c, 0x8d, 0x8e, 0x8e, 0x8e, 0x8d, + 0x8b, 0x8a, 0x88, 0x86, 0x83, 0x81, 0x7f, 0x7e, 0x7c, 0x7b, 0x7a, + 0x79, 0x78, 0x78, 0x77, 0x77, 0x77, 0x76, 0x76, 0x77, 0x77, 0x78, + 0x79, 0x7a, 0x7b, 0x7d, 0x7e, 0x80, 0x81, 0x83, 0x85, 0x87, 0x89, + 0x8a, 0x8a, 0x8b, 0x8b, 0x8a, 0x89, 0x88, 0x86, 0x84, 0x82, 0x81, + 0x7f, 0x7e, 0x7c, 0x7b, 0x7a, 0x7a, 0x79, 0x79, 0x79, 0x79, 0x79, + 0x79, 0x79, 0x79, 0x7a, 0x7a, 0x7b, 0x7b, 0x7c, 0x7d, 0x7e, 0x80, + 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x86, 0x85, 0x84, 0x83, 0x82, 0x80, 0x7f, 0x7e, 0x7e, 0x7d, 0x7c, + 0x7c, 0x7c, 0x7c, 0x7b, 0x7b, 0x7b, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, + 0x7d, 0x7d, 0x7e, 0x7e, 0x7f, 0x7f, 0x80, 0x81, 0x81, 0x82, 0x82, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x82, 0x82, 0x81, 0x81, 0x80, + 0x80, 0x7f, 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, + 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, + 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x80, + 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, + 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, + 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, + 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, + 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x80, + 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x80, + 0x7f, + }, + { // 1 + 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x80, + 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x81, 0x80, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x82, 0x81, 0x81, 0x81, 0x81, 0x81, 0x80, 0x7f, + 0x7f, 0x7f, 0x7e, 0x7e, 0x7d, 0x7d, 0x7c, 0x7c, 0x7c, 0x7b, 0x7d, + 0x7b, 0x7e, 0x7c, 0x7e, 0x7f, 0x7e, 0x82, 0x82, 0x83, 0x85, 0x86, + 0x87, 0x89, 0x88, 0x8a, 0x89, 0x89, 0x87, 0x88, 0x84, 0x84, 0x7f, + 0x7e, 0x7a, 0x77, 0x74, 0x71, 0x6e, 0x6c, 0x6a, 0x6a, 0x6b, 0x6b, + 0x71, 0x70, 0x78, 0x79, 0x80, 0x84, 0x8a, 0x8e, 0x94, 0x97, 0x9c, + 0x9e, 0x9e, 0xa2, 0x9d, 0x9e, 0x9a, 0x95, 0x92, 0x8c, 0x85, 0x80, + 0x77, 0x73, 0x6a, 0x66, 0x60, 0x5c, 0x58, 0x58, 0x55, 0x59, 0x5b, + 0x5d, 0x67, 0x69, 0x72, 0x79, 0x80, 0x88, 0x91, 0x95, 0x9d, 0xa1, + 0xa5, 0xa8, 0xa9, 0xa8, 0xa9, 0xa3, 0xa2, 0x9b, 0x96, 0x90, 0x89, + 0x82, 0x7a, 0x72, 0x6a, 0x65, 0x5d, 0x5a, 0x53, 0x55, 0x4f, 0x56, + 0x55, 0x5c, 0x62, 0x67, 0x6f, 0x77, 0x7f, 0x88, 0x90, 0x96, 0xa0, + 0xa1, 0xaa, 0xa8, 0xad, 0xab, 0xaa, 0xa6, 0xa2, 0x9c, 0x97, 0x8e, + 0x89, 0x80, 0x78, 0x70, 0x67, 0x61, 0x5a, 0x56, 0x52, 0x52, 0x4f, + 0x55, 0x53, 0x5d, 0x61, 0x68, 0x71, 0x78, 0x80, 0x8b, 0x90, 0x9b, + 0xa0, 0xa5, 0xab, 0xab, 0xae, 0xac, 0xab, 0xa6, 0xa3, 0x9a, 0x97, + 0x8d, 0x87, 0x7d, 0x76, 0x6c, 0x65, 0x5d, 0x58, 0x53, 0x50, 0x50, + 0x4e, 0x56, 0x53, 0x5f, 0x61, 0x6a, 0x73, 0x7a, 0x83, 0x8d, 0x93, + 0x9e, 0xa2, 0xa8, 0xad, 0xae, 0xb0, 0xae, 0xad, 0xa7, 0xa4, 0x9b, + 0x96, 0x8d, 0x86, 0x7b, 0x74, 0x68, 0x63, 0x5a, 0x56, 0x4f, 0x50, + 0x4b, 0x4e, 0x53, 0x52, 0x5f, 0x60, 0x6b, 0x74, 0x7c, 0x86, 0x91, + 0x96, 0xa2, 0xa5, 0xae, 0xaf, 0xb3, 0xb2, 0xb3, 0xad, 0xaa, 0xa2, + 0x9d, 0x94, 0x8c, 0x82, 0x79, 0x70, 0x64, 0x5f, 0x55, 0x53, 0x4c, + 0x4e, 0x49, 0x52, 0x4d, 0x5d, 0x59, 0x6a, 0x6d, 0x75, 0x85, 0x85, + 0x95, 0x9b, 0x9f, 0xaa, 0xab, 0xac, 0xb5, 0xa8, 0xb3, 0xa4, 0xa6, + 0x9e, 0x96, 0x92, 0x88, 0x7f, 0x7b, 0x6c, 0x68, 0x61, 0x57, 0x59, + 0x4f, 0x53, 0x50, 0x52, 0x55, 0x5a, 0x60, 0x66, 0x6f, 0x76, 0x80, + 0x88, 0x92, 0x99, 0xa2, 0xa6, 0xac, 0xb0, 0xaf, 0xb3, 0xad, 0xaa, + 0xa6, 0x9d, 0x98, 0x8f, 0x86, 0x7e, 0x74, 0x6b, 0x62, 0x5c, 0x56, + 0x50, 0x50, 0x4d, 0x4d, 0x54, 0x52, 0x5e, 0x61, 0x68, 0x75, 0x79, + 0x84, 0x8f, 0x94, 0x9e, 0xa4, 0xa8, 0xaf, 0xb0, 0xb1, 0xb2, 0xad, + 0xaa, 0xa4, 0x9b, 0x98, 0x8b, 0x86, 0x7a, 0x72, 0x68, 0x61, 0x58, + 0x55, 0x4d, 0x4f, 0x4a, 0x4e, 0x52, 0x53, 0x5e, 0x61, 0x6c, 0x74, + 0x7e, 0x86, 0x93, 0x96, 0xa4, 0xa4, 0xae, 0xaf, 0xb1, 0xb5, 0xae, + 0xb1, 0xa7, 0xa2, 0x9d, 0x91, 0x8c, 0x81, 0x76, 0x71, 0x61, 0x5f, + 0x55, 0x51, 0x4e, 0x4c, 0x49, 0x51, 0x4e, 0x59, 0x5f, 0x63, 0x70, + 0x76, 0x81, 0x8b, 0x93, 0x9b, 0xa4, 0xa7, 0xaf, 0xaf, 0xb4, 0xb0, + 0xb2, 0xab, 0xa8, 0xa0, 0x9a, 0x90, 0x88, 0x7e, 0x75, 0x6b, 0x62, + 0x5b, 0x54, 0x4f, 0x4d, 0x4c, 0x49, 0x52, 0x4e, 0x5c, 0x5e, 0x68, + 0x71, 0x7a, 0x83, 0x8f, 0x96, 0x9f, 0xa7, 0xa9, 0xb3, 0xaf, 0xb7, + 0xb2, 0xb0, 0xae, 0xa4, 0xa0, 0x97, 0x8d, 0x87, 0x79, 0x74, 0x67, + 0x60, 0x58, 0x51, 0x4d, 0x4c, 0x49, 0x4e, 0x4e, 0x53, 0x5d, 0x5e, + 0x6d, 0x71, 0x7d, 0x86, 0x90, 0x98, 0xa2, 0xa6, 0xae, 0xb0, 0xb2, + 0xb5, 0xb1, 0xb0, 0xab, 0xa4, 0x9f, 0x95, 0x8d, 0x85, 0x78, 0x73, + 0x64, 0x5f, 0x55, 0x50, 0x4b, 0x4a, 0x47, 0x4d, 0x4e, 0x52, 0x5e, + 0x5f, 0x6e, 0x74, 0x7f, 0x8a, 0x93, 0x9b, 0xa6, 0xa8, 0xb1, 0xb2, + 0xb4, 0xb7, 0xb1, 0xb2, 0xa8, 0xa3, 0x9c, 0x92, 0x8b, 0x81, 0x77, + 0x6f, 0x62, 0x5d, 0x53, 0x4e, 0x4a, 0x49, 0x48, 0x4d, 0x4c, 0x57, + 0x5b, 0x63, 0x70, 0x75, 0x84, 0x8b, 0x96, 0xa0, 0xa8, 0xac, 0xb5, + 0xb3, 0xb9, 0xb6, 0xb3, 0xb1, 0xa8, 0xa2, 0x9a, 0x8f, 0x8a, 0x7d, + 0x75, 0x6b, 0x60, 0x5a, 0x51, 0x4d, 0x48, 0x49, 0x46, 0x4e, 0x4b, + 0x59, 0x5a, 0x66, 0x6f, 0x77, 0x84, 0x8c, 0x97, 0xa1, 0xa8, 0xad, + 0xb6, 0xb4, 0xbb, 0xb5, 0xb5, 0xaf, 0xa7, 0xa2, 0x99, 0x90, 0x89, + 0x7b, 0x75, 0x68, 0x60, 0x57, 0x50, 0x4b, 0x49, 0x47, 0x48, 0x4c, + 0x4e, 0x59, 0x5b, 0x68, 0x6e, 0x7a, 0x84, 0x8f, 0x98, 0xa3, 0xa9, + 0xb0, 0xb4, 0xb7, 0xb8, 0xb6, 0xb3, 0xae, 0xa7, 0xa0, 0x97, 0x8e, + 0x86, 0x7a, 0x72, 0x65, 0x5f, 0x54, 0x50, 0x48, 0x4a, 0x44, 0x4b, + 0x4a, 0x51, 0x5a, 0x5d, 0x6c, 0x70, 0x7f, 0x88, 0x93, 0x9c, 0xa7, + 0xab, 0xb3, 0xb6, 0xb7, 0xb8, 0xb5, 0xb1, 0xac, 0xa3, 0x9e, 0x92, + 0x8c, 0x81, 0x78, 0x6e, 0x63, 0x5b, 0x53, 0x4d, 0x49, 0x48, 0x45, + 0x4c, 0x4a, 0x56, 0x58, 0x63, 0x6c, 0x75, 0x82, 0x8c, 0x96, 0xa1, + 0xa8, 0xaf, 0xb5, 0xb6, 0xba, 0xb7, 0xb5, 0xb0, 0xaa, 0xa2, 0x9b, + 0x91, 0x8a, 0x7d, 0x77, 0x69, 0x62, 0x57, 0x52, 0x4b, 0x49, 0x46, + 0x48, 0x4b, 0x4c, 0x59, 0x59, 0x69, 0x6e, 0x7a, 0x85, 0x8f, 0x99, + 0xa4, 0xaa, 0xb2, 0xb6, 0xb7, 0xba, 0xb5, 0xb4, 0xae, 0xa7, 0xa0, + 0x97, 0x8f, 0x85, 0x7b, 0x73, 0x66, 0x60, 0x55, 0x50, 0x4a, 0x48, + 0x46, 0x49, 0x4a, 0x50, 0x58, 0x5d, 0x6a, 0x71, 0x7d, 0x88, 0x92, + 0x9c, 0xa6, 0xac, 0xb3, 0xb6, 0xb8, 0xb9, 0xb5, 0xb2, 0xac, 0xa5, + 0x9e, 0x93, 0x8d, 0x81, 0x79, 0x6e, 0x63, 0x5d, 0x52, 0x4f, 0x48, + 0x48, 0x45, 0x4b, 0x4a, 0x53, 0x59, 0x60, 0x6d, 0x73, 0x80, 0x8a, + 0x94, 0x9e, 0xa8, 0xac, 0xb5, 0xb5, 0xb9, 0xb8, 0xb5, 0xb1, 0xab, + 0xa3, 0x9d, 0x92, 0x8b, 0x7f, 0x76, 0x6c, 0x62, 0x5a, 0x52, 0x4d, + 0x48, 0x48, 0x45, 0x4d, 0x49, 0x58, 0x58, 0x65, 0x6d, 0x76, 0x83, + 0x8b, 0x97, 0xa0, 0xa9, 0xae, 0xb6, 0xb5, 0xb9, 0xb6, 0xb4, 0xae, + 0xa8, 0xa1, 0x99, 0x8f, 0x88, 0x7c, 0x76, 0x68, 0x62, 0x58, 0x52, + 0x4d, 0x49, 0x47, 0x47, 0x4c, 0x4d, 0x59, 0x5a, 0x69, 0x6d, 0x7a, + 0x84, 0x8e, 0x99, 0xa2, 0xa9, 0xb1, 0xb4, 0xb7, 0xb7, 0xb5, 0xb3, + 0xac, 0xa7, 0x9f, 0x97, 0x8e, 0x85, 0x7b, 0x73, 0x68, 0x61, 0x57, + 0x54, 0x4b, 0x4c, 0x46, 0x4b, 0x4c, 0x50, 0x59, 0x5e, 0x68, 0x71, + 0x7a, 0x86, 0x90, 0x99, 0xa5, 0xa9, 0xb2, 0xb4, 0xb8, 0xb7, 0xb6, + 0xb1, 0xad, 0xa5, 0x9e, 0x96, 0x8d, 0x84, 0x7b, 0x71, 0x67, 0x5f, + 0x55, 0x52, 0x4a, 0x4b, 0x45, 0x4c, 0x4a, 0x53, 0x58, 0x5f, 0x69, + 0x72, 0x7c, 0x87, 0x92, 0x9b, 0xa6, 0xab, 0xb4, 0xb4, 0xb8, 0xb6, + 0xb5, 0xaf, 0xab, 0xa2, 0x9c, 0x92, 0x8b, 0x80, 0x78, 0x6c, 0x64, + 0x5b, 0x55, 0x4e, 0x4c, 0x49, 0x4a, 0x4d, 0x4e, 0x59, 0x5b, 0x68, + 0x6f, 0x79, 0x84, 0x8f, 0x97, 0xa4, 0xa8, 0xb1, 0xb3, 0xb7, 0xb6, + 0xb5, 0xb0, 0xab, 0xa4, 0x9d, 0x95, 0x8c, 0x84, 0x7a, 0x71, 0x67, + 0x5f, 0x56, 0x52, 0x4b, 0x4d, 0x47, 0x50, 0x4c, 0x57, 0x5a, 0x63, + 0x6d, 0x75, 0x81, 0x8b, 0x94, 0x9e, 0xa6, 0xab, 0xb2, 0xb3, 0xb6, + 0xb3, 0xb2, 0xab, 0xa7, 0x9f, 0x98, 0x90, 0x89, 0x7e, 0x78, 0x6b, + 0x65, 0x59, 0x55, 0x4d, 0x4e, 0x48, 0x4d, 0x4d, 0x52, 0x5a, 0x5e, + 0x6b, 0x70, 0x7e, 0x85, 0x92, 0x98, 0xa4, 0xa7, 0xb1, 0xb0, 0xb6, + 0xb2, 0xb3, 0xad, 0xa8, 0xa1, 0x9a, 0x93, 0x8b, 0x82, 0x79, 0x70, + 0x67, 0x5e, 0x57, 0x51, 0x4d, 0x4c, 0x4a, 0x50, 0x4f, 0x59, 0x5b, + 0x67, 0x6e, 0x79, 0x82, 0x8e, 0x94, 0xa0, 0xa4, 0xac, 0xaf, 0xb2, + 0xb3, 0xb2, 0xaf, 0xaa, 0xa3, 0x9d, 0x95, 0x8d, 0x86, 0x7b, 0x75, + 0x69, 0x63, 0x5a, 0x55, 0x4f, 0x50, 0x49, 0x51, 0x4d, 0x57, 0x5b, + 0x62, 0x6d, 0x73, 0x80, 0x88, 0x92, 0x9b, 0xa3, 0xa8, 0xaf, 0xb0, + 0xb5, 0xb0, 0xb2, 0xa9, 0xa7, 0x9e, 0x98, 0x90, 0x89, 0x7f, 0x78, + 0x6d, 0x67, 0x5d, 0x58, 0x52, 0x4e, 0x4e, 0x4a, 0x51, 0x4e, 0x5a, + 0x5b, 0x67, 0x6d, 0x78, 0x81, 0x8c, 0x93, 0x9e, 0xa3, 0xaa, 0xaf, + 0xb1, 0xb4, 0xb1, 0xb0, 0xaa, 0xa6, 0x9d, 0x98, 0x8f, 0x89, 0x7e, + 0x77, 0x6c, 0x66, 0x5c, 0x58, 0x50, 0x4f, 0x4c, 0x4d, 0x50, 0x52, + 0x5b, 0x5e, 0x6a, 0x6f, 0x7a, 0x84, 0x8d, 0x95, 0x9e, 0xa3, 0xab, + 0xac, 0xb1, 0xb0, 0xb0, 0xac, 0xa8, 0xa2, 0x9c, 0x95, 0x8e, 0x86, + 0x7d, 0x76, 0x6c, 0x65, 0x5b, 0x59, 0x50, 0x51, 0x4b, 0x50, 0x4f, + 0x55, 0x5b, 0x60, 0x6b, 0x71, 0x7c, 0x85, 0x8f, 0x96, 0xa0, 0xa4, + 0xac, 0xac, 0xb1, 0xaf, 0xb0, 0xaa, 0xa7, 0xa1, 0x99, 0x94, 0x8b, + 0x85, 0x7c, 0x74, 0x6c, 0x64, 0x5d, 0x59, 0x51, 0x53, 0x4b, 0x53, + 0x50, 0x57, 0x5e, 0x61, 0x6d, 0x71, 0x7e, 0x85, 0x8f, 0x97, 0xa0, + 0xa4, 0xac, 0xab, 0xb0, 0xae, 0xae, 0xab, 0xa5, 0xa1, 0x98, 0x93, + 0x8b, 0x84, 0x7c, 0x73, 0x6c, 0x64, 0x5c, 0x59, 0x51, 0x53, 0x4d, + 0x53, 0x52, 0x57, 0x5f, 0x62, 0x6e, 0x73, 0x7d, 0x86, 0x8f, 0x97, + 0x9f, 0xa3, 0xaa, 0xaa, 0xaf, 0xab, 0xad, 0xa7, 0xa3, 0x9e, 0x96, + 0x92, 0x89, 0x83, 0x7c, 0x73, 0x6c, 0x64, 0x5e, 0x59, 0x53, 0x55, + 0x4e, 0x56, 0x53, 0x5b, 0x60, 0x64, 0x6f, 0x75, 0x7e, 0x88, 0x8f, + 0x98, 0xa0, 0xa3, 0xab, 0xa9, 0xae, 0xaa, 0xab, 0xa5, 0xa3, 0x9b, + 0x96, 0x8f, 0x88, 0x82, 0x7a, 0x72, 0x6c, 0x64, 0x5e, 0x59, 0x54, + 0x55, 0x4f, 0x57, 0x53, 0x5d, 0x60, 0x67, 0x70, 0x76, 0x80, 0x89, + 0x90, 0x9a, 0x9f, 0xa4, 0xaa, 0xa9, 0xae, 0xa8, 0xaa, 0xa4, 0xa2, + 0x9b, 0x95, 0x90, 0x88, 0x83, 0x7b, 0x74, 0x6d, 0x66, 0x5f, 0x5c, + 0x54, 0x57, 0x50, 0x56, 0x56, 0x5a, 0x62, 0x64, 0x70, 0x74, 0x7e, + 0x87, 0x8e, 0x96, 0x9e, 0xa1, 0xa8, 0xa8, 0xab, 0xaa, 0xa8, 0xa4, + 0xa1, 0x9b, 0x95, 0x90, 0x88, 0x83, 0x7b, 0x75, 0x6e, 0x69, 0x60, + 0x5f, 0x57, 0x58, 0x54, 0x56, 0x59, 0x5a, 0x62, 0x64, 0x6e, 0x73, + 0x7c, 0x84, 0x8c, 0x93, 0x9b, 0x9e, 0xa5, 0xa6, 0xa7, 0xa9, 0xa5, + 0xa5, 0x9e, 0x9b, 0x95, 0x8f, 0x89, 0x83, 0x7b, 0x77, 0x6e, 0x6a, + 0x63, 0x5f, 0x5c, 0x59, 0x59, 0x58, 0x5c, 0x5c, 0x65, 0x64, 0x71, + 0x73, 0x7c, 0x84, 0x8a, 0x91, 0x99, 0x9c, 0xa3, 0xa4, 0xa5, 0xa9, + 0xa2, 0xa5, 0x9d, 0x9b, 0x94, 0x90, 0x88, 0x84, 0x7a, 0x78, 0x6e, + 0x6b, 0x63, 0x61, 0x5c, 0x5b, 0x5a, 0x59, 0x5e, 0x5d, 0x66, 0x67, + 0x71, 0x74, 0x7e, 0x83, 0x8c, 0x90, 0x9a, 0x9b, 0xa3, 0xa3, 0xa5, + 0xa6, 0xa1, 0xa2, 0x9b, 0x99, 0x92, 0x8d, 0x87, 0x81, 0x7a, 0x75, + 0x6c, 0x6b, 0x62, 0x62, 0x5d, 0x5d, 0x5c, 0x5c, 0x61, 0x60, 0x6a, + 0x69, 0x75, 0x77, 0x80, 0x86, 0x8d, 0x93, 0x9a, 0x9d, 0xa1, 0xa3, + 0xa2, 0xa4, 0xa0, 0x9f, 0x9a, 0x95, 0x90, 0x8a, 0x83, 0x7f, 0x76, + 0x74, 0x6a, 0x69, 0x62, 0x61, 0x5e, 0x5e, 0x5c, 0x60, 0x62, 0x66, + 0x6c, 0x6f, 0x78, 0x7b, 0x84, 0x89, 0x90, 0x95, 0x9c, 0x9c, 0xa3, + 0x9f, 0xa4, 0xa0, 0x9e, 0x9b, 0x95, 0x91, 0x8b, 0x85, 0x80, 0x79, + 0x73, 0x6e, 0x68, 0x65, 0x61, 0x61, 0x5d, 0x60, 0x5f, 0x64, 0x65, + 0x6c, 0x6f, 0x76, 0x7c, 0x82, 0x89, 0x8e, 0x94, 0x99, 0x9c, 0xa0, + 0xa0, 0xa0, 0xa2, 0x9c, 0x9d, 0x95, 0x93, 0x8d, 0x86, 0x82, 0x7b, + 0x75, 0x71, 0x6a, 0x68, 0x63, 0x61, 0x5f, 0x5f, 0x60, 0x62, 0x65, + 0x69, 0x6e, 0x73, 0x7a, 0x7e, 0x85, 0x8a, 0x90, 0x95, 0x99, 0x9c, + 0x9f, 0x9f, 0xa2, 0x9d, 0x9e, 0x99, 0x95, 0x90, 0x8a, 0x85, 0x7f, + 0x79, 0x75, 0x6d, 0x6b, 0x65, 0x63, 0x62, 0x5f, 0x61, 0x60, 0x65, + 0x66, 0x6d, 0x6f, 0x77, 0x7a, 0x81, 0x86, 0x8c, 0x91, 0x96, 0x99, + 0x9c, 0x9d, 0x9f, 0x9e, 0x9d, 0x9b, 0x95, 0x94, 0x8c, 0x89, 0x81, + 0x7d, 0x77, 0x73, 0x6d, 0x6b, 0x65, 0x65, 0x61, 0x63, 0x61, 0x64, + 0x66, 0x69, 0x6f, 0x71, 0x79, 0x7b, 0x84, 0x86, 0x8e, 0x91, 0x95, + 0x99, 0x9b, 0x9d, 0x9e, 0x9c, 0x9c, 0x97, 0x95, 0x8f, 0x8b, 0x86, + 0x80, 0x7c, 0x76, 0x71, 0x6d, 0x69, 0x66, 0x65, 0x62, 0x64, 0x63, + 0x67, 0x68, 0x6d, 0x70, 0x76, 0x7b, 0x7f, 0x85, 0x88, 0x8e, 0x91, + 0x95, 0x97, 0x99, 0x9a, 0x9a, 0x9a, 0x97, 0x95, 0x91, 0x8d, 0x89, + 0x84, 0x80, 0x7a, 0x76, 0x70, 0x6d, 0x6a, 0x67, 0x66, 0x65, 0x65, + 0x67, 0x69, 0x6b, 0x71, 0x74, 0x79, 0x7d, 0x82, 0x86, 0x8b, 0x8f, + 0x92, 0x95, 0x98, 0x99, 0x99, 0x9a, 0x97, 0x96, 0x92, 0x8f, 0x8a, + 0x86, 0x81, 0x7c, 0x77, 0x73, 0x6e, 0x6b, 0x69, 0x67, 0x66, 0x66, + 0x67, 0x69, 0x6c, 0x70, 0x73, 0x78, 0x7c, 0x81, 0x84, 0x8a, 0x8e, + 0x91, 0x95, 0x96, 0x98, 0x98, 0x99, 0x95, 0x95, 0x90, 0x8e, 0x87, + 0x84, 0x7e, 0x79, 0x74, 0x70, 0x6d, 0x69, 0x69, 0x67, 0x68, 0x68, + 0x6b, 0x6c, 0x71, 0x73, 0x79, 0x7b, 0x81, 0x83, 0x89, 0x8b, 0x8f, + 0x92, 0x94, 0x96, 0x96, 0x97, 0x95, 0x95, 0x91, 0x8f, 0x8a, 0x86, + 0x82, 0x7d, 0x77, 0x75, 0x70, 0x6d, 0x6b, 0x69, 0x69, 0x69, 0x6a, + 0x6c, 0x6e, 0x70, 0x73, 0x77, 0x7a, 0x7f, 0x82, 0x86, 0x8a, 0x8b, + 0x8f, 0x90, 0x93, 0x93, 0x94, 0x93, 0x93, 0x91, 0x8e, 0x8c, 0x87, + 0x84, 0x80, 0x7c, 0x79, 0x75, 0x72, 0x71, 0x6e, 0x6d, 0x6d, 0x6d, + 0x6e, 0x70, 0x72, 0x74, 0x77, 0x7a, 0x7d, 0x81, 0x83, 0x87, 0x89, + 0x8b, 0x8d, 0x8f, 0x90, 0x8f, 0x90, 0x8f, 0x8e, 0x8c, 0x8a, 0x87, + 0x85, 0x81, 0x7e, 0x7c, 0x78, 0x77, 0x74, 0x73, 0x71, 0x71, 0x70, + 0x71, 0x72, 0x74, 0x75, 0x78, 0x79, 0x7d, 0x7e, 0x81, 0x84, 0x85, + 0x88, 0x88, 0x8a, 0x8a, 0x8b, 0x8b, 0x8b, 0x8a, 0x8a, 0x88, 0x86, + 0x85, 0x82, 0x80, 0x7e, 0x7c, 0x7a, 0x79, 0x76, 0x77, 0x75, 0x75, + 0x75, 0x76, 0x76, 0x78, 0x79, 0x7b, 0x7c, 0x7e, 0x80, 0x81, 0x83, + 0x84, 0x86, 0x86, 0x87, 0x87, 0x88, 0x87, 0x87, 0x86, 0x86, 0x84, + 0x84, 0x82, 0x81, 0x7f, 0x7e, 0x7d, 0x7b, 0x7b, 0x79, 0x79, 0x78, + 0x78, 0x78, 0x7a, 0x79, 0x7c, 0x7b, 0x7e, 0x7e, 0x7f, 0x81, 0x82, + 0x83, 0x83, 0x84, 0x83, 0x85, 0x84, 0x85, 0x84, 0x84, 0x83, 0x83, + 0x81, 0x81, 0x80, 0x7f, 0x7f, 0x7d, 0x7d, 0x7c, 0x7c, 0x7b, 0x7c, + 0x7b, 0x7c, 0x7c, 0x7d, 0x7d, 0x7f, 0x7f, 0x80, 0x80, 0x81, 0x81, + 0x82, 0x82, 0x81, 0x82, 0x81, 0x82, 0x81, 0x81, 0x81, 0x81, 0x80, + 0x80, 0x7f, 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, + 0x7e, 0x7e, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, + 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, + 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, + 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, + 0x80, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x80, + 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, + 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, + 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x80, + 0x80, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, + 0x7f, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x80, + 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x7f, + 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x80, 0x80, + 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x7f, + 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, + 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, + 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, + 0x7f, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x7f, + 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, + }, + { // 2 + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7e, 0x7f, 0x7f, 0x7f, 0x7e, 0x7f, 0x80, 0x7f, 0x7f, + 0x7f, 0x7e, 0x7f, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, + 0x7f, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, 0x80, 0x7f, + 0x7f, 0x7f, 0x7f, 0x80, 0x7e, 0x7f, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7e, 0x7f, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7e, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x7e, 0x7f, + 0x7f, 0x80, 0x7f, 0x80, 0x7e, 0x80, 0x7e, 0x81, 0x7f, 0x89, 0x87, + 0x7d, 0x78, 0x76, 0x7c, 0x87, 0x88, 0x82, 0x7a, 0x72, 0x73, 0x79, + 0x80, 0x81, 0x7d, 0x74, 0x73, 0x77, 0x81, 0x7c, 0x7f, 0x75, 0x90, + 0x9f, 0x92, 0x81, 0x6b, 0x6a, 0x83, 0x97, 0x94, 0x8c, 0x7c, 0x78, + 0x80, 0x88, 0x81, 0x82, 0x7c, 0x81, 0x84, 0x7e, 0x77, 0x76, 0x7b, + 0x81, 0x81, 0x73, 0x6b, 0x65, 0x6b, 0x70, 0x7d, 0x84, 0x8f, 0xa8, + 0x91, 0x73, 0x65, 0x66, 0x7f, 0x95, 0x97, 0x93, 0x89, 0x7d, 0x7a, + 0x79, 0x7e, 0x83, 0x84, 0x85, 0x84, 0x7d, 0x7a, 0x73, 0x77, 0x7e, + 0x83, 0x82, 0x80, 0x73, 0x6b, 0x69, 0x69, 0x6e, 0x7b, 0x82, 0x88, + 0xa4, 0x9b, 0x83, 0x70, 0x66, 0x76, 0x8f, 0x9b, 0x9f, 0x94, 0x83, + 0x7a, 0x76, 0x7d, 0x83, 0x85, 0x87, 0x80, 0x79, 0x73, 0x6f, 0x74, + 0x7c, 0x7d, 0x75, 0x68, 0x62, 0x60, 0x77, 0x86, 0x90, 0xad, 0x99, + 0x80, 0x6b, 0x63, 0x7e, 0x9a, 0xa0, 0xa3, 0x92, 0x83, 0x7c, 0x77, + 0x7f, 0x83, 0x89, 0x86, 0x7b, 0x71, 0x6f, 0x6d, 0x76, 0x7a, 0x76, + 0x6d, 0x64, 0x55, 0x6c, 0x82, 0x93, 0xba, 0xa5, 0x7e, 0x64, 0x5d, + 0x78, 0x9e, 0xa8, 0xa4, 0x93, 0x83, 0x79, 0x75, 0x7c, 0x84, 0x89, + 0x89, 0x7b, 0x6e, 0x64, 0x6e, 0x79, 0x75, 0x6f, 0x68, 0x56, 0x5e, + 0x7a, 0x7f, 0xb2, 0xb8, 0x8e, 0x6c, 0x57, 0x6a, 0x95, 0xae, 0xaa, + 0xa0, 0x8a, 0x7c, 0x77, 0x7c, 0x83, 0x89, 0x8d, 0x81, 0x6f, 0x63, + 0x63, 0x6e, 0x71, 0x6f, 0x6a, 0x56, 0x60, 0x7d, 0x77, 0xa3, 0xb3, + 0x92, 0x7a, 0x5e, 0x66, 0x8c, 0xab, 0xaa, 0x9f, 0x8a, 0x7d, 0x77, + 0x7c, 0x7f, 0x87, 0x8b, 0x7d, 0x6c, 0x60, 0x65, 0x6d, 0x73, 0x6d, + 0x5e, 0x56, 0x78, 0x76, 0x8f, 0xb8, 0x9c, 0x88, 0x6a, 0x61, 0x81, + 0xa4, 0xa9, 0x9f, 0x94, 0x85, 0x7f, 0x7e, 0x7c, 0x81, 0x8b, 0x86, + 0x72, 0x64, 0x65, 0x6d, 0x6d, 0x68, 0x61, 0x5a, 0x77, 0x7f, 0x77, + 0xac, 0xaa, 0x89, 0x74, 0x59, 0x77, 0xa2, 0xac, 0xa0, 0x97, 0x87, + 0x85, 0x7c, 0x74, 0x83, 0x90, 0x87, 0x73, 0x60, 0x62, 0x6a, 0x64, + 0x69, 0x65, 0x5f, 0x7d, 0x74, 0x75, 0xb1, 0xa4, 0x8b, 0x75, 0x64, + 0x7a, 0xa3, 0xa7, 0x9c, 0x99, 0x87, 0x85, 0x7c, 0x79, 0x84, 0x8f, + 0x81, 0x71, 0x63, 0x65, 0x6d, 0x62, 0x64, 0x60, 0x6b, 0x81, 0x6b, + 0x7b, 0xb3, 0xa0, 0x89, 0x72, 0x67, 0x8a, 0xa5, 0x9e, 0x97, 0x98, + 0x8d, 0x87, 0x79, 0x77, 0x84, 0x8e, 0x7d, 0x6a, 0x60, 0x66, 0x6b, + 0x63, 0x64, 0x61, 0x6d, 0x7c, 0x6b, 0x81, 0xaf, 0x9f, 0x86, 0x71, + 0x6f, 0x8b, 0xa6, 0x9b, 0x98, 0x9e, 0x8a, 0x81, 0x76, 0x7c, 0x90, + 0x86, 0x73, 0x6c, 0x68, 0x68, 0x5f, 0x63, 0x6a, 0x6b, 0x77, 0x6a, + 0x66, 0x99, 0xab, 0x9c, 0x7c, 0x67, 0x7e, 0x9d, 0xa1, 0x97, 0x9b, + 0x94, 0x88, 0x7e, 0x73, 0x88, 0x90, 0x7e, 0x71, 0x68, 0x6b, 0x63, + 0x5d, 0x61, 0x6a, 0x76, 0x79, 0x59, 0x72, 0xad, 0xa5, 0x87, 0x6d, + 0x71, 0x95, 0xa9, 0x94, 0x97, 0x9e, 0x8d, 0x86, 0x75, 0x80, 0x99, + 0x89, 0x71, 0x67, 0x6e, 0x70, 0x62, 0x61, 0x66, 0x67, 0x78, 0x6d, + 0x5a, 0x8f, 0xa8, 0x8f, 0x80, 0x72, 0x7f, 0x98, 0x9a, 0x94, 0xa2, + 0x99, 0x84, 0x81, 0x78, 0x8d, 0x8f, 0x82, 0x73, 0x6c, 0x6b, 0x67, + 0x60, 0x6b, 0x6d, 0x68, 0x73, 0x5f, 0x6d, 0x9a, 0xa4, 0x82, 0x7b, + 0x77, 0x87, 0x98, 0x92, 0x98, 0xa5, 0x96, 0x7c, 0x80, 0x79, 0x91, + 0x8b, 0x7b, 0x75, 0x73, 0x6c, 0x65, 0x67, 0x69, 0x6b, 0x64, 0x7b, + 0x6b, 0x60, 0x96, 0xa5, 0x86, 0x7d, 0x76, 0x85, 0x9a, 0x94, 0x93, + 0xa4, 0x96, 0x7c, 0x81, 0x81, 0x8c, 0x88, 0x7a, 0x74, 0x74, 0x6b, + 0x67, 0x6d, 0x69, 0x61, 0x6b, 0x7a, 0x64, 0x67, 0x98, 0xa1, 0x85, + 0x7d, 0x7a, 0x8d, 0x9e, 0x91, 0x90, 0xa3, 0x96, 0x7e, 0x80, 0x81, + 0x8d, 0x89, 0x77, 0x76, 0x77, 0x6a, 0x61, 0x63, 0x6f, 0x74, 0x61, + 0x6e, 0x6e, 0x61, 0x84, 0x9d, 0x9a, 0x87, 0x77, 0x80, 0x8a, 0x92, + 0x9c, 0xa3, 0x9b, 0x82, 0x7a, 0x81, 0x8b, 0x8b, 0x82, 0x77, 0x76, + 0x6e, 0x62, 0x69, 0x72, 0x69, 0x62, 0x6c, 0x71, 0x69, 0x7d, 0x92, + 0x8e, 0x8f, 0x7d, 0x7e, 0x90, 0x93, 0x95, 0x97, 0x9b, 0x90, 0x7f, + 0x7f, 0x84, 0x89, 0x88, 0x7c, 0x78, 0x74, 0x6c, 0x67, 0x67, 0x6c, + 0x63, 0x65, 0x76, 0x6b, 0x60, 0x8b, 0x9e, 0x88, 0x86, 0x84, 0x88, + 0x89, 0x93, 0x98, 0x98, 0x98, 0x8e, 0x87, 0x85, 0x81, 0x82, 0x86, + 0x82, 0x7b, 0x71, 0x69, 0x69, 0x67, 0x67, 0x66, 0x6e, 0x7c, 0x63, + 0x56, 0x8e, 0x9f, 0x8a, 0x85, 0x7c, 0x88, 0x91, 0x8e, 0x8b, 0x9c, + 0x9e, 0x8d, 0x83, 0x82, 0x83, 0x84, 0x7f, 0x81, 0x7e, 0x73, 0x6c, + 0x68, 0x6d, 0x6c, 0x65, 0x62, 0x6f, 0x77, 0x64, 0x72, 0x9b, 0x8d, + 0x82, 0x8c, 0x87, 0x83, 0x90, 0x95, 0x92, 0x97, 0x95, 0x8d, 0x84, + 0x82, 0x87, 0x82, 0x7f, 0x7e, 0x77, 0x75, 0x70, 0x69, 0x67, 0x6d, + 0x65, 0x5e, 0x74, 0x78, 0x6a, 0x85, 0x95, 0x84, 0x82, 0x85, 0x86, + 0x92, 0x97, 0x90, 0x92, 0x95, 0x91, 0x8a, 0x87, 0x86, 0x82, 0x7f, + 0x80, 0x83, 0x7a, 0x73, 0x6d, 0x68, 0x6a, 0x68, 0x64, 0x63, 0x6f, + 0x76, 0x67, 0x7a, 0x97, 0x85, 0x7c, 0x8b, 0x8f, 0x89, 0x8f, 0x95, + 0x93, 0x95, 0x91, 0x8c, 0x8c, 0x8a, 0x83, 0x7f, 0x80, 0x80, 0x7b, + 0x7b, 0x7a, 0x6b, 0x63, 0x6a, 0x68, 0x5f, 0x62, 0x75, 0x78, 0x6b, + 0x7b, 0x91, 0x89, 0x84, 0x8b, 0x89, 0x8b, 0x95, 0x97, 0x90, 0x93, + 0x91, 0x8f, 0x8c, 0x89, 0x85, 0x80, 0x7d, 0x7b, 0x7d, 0x7d, 0x7a, + 0x6d, 0x60, 0x63, 0x69, 0x66, 0x63, 0x6b, 0x79, 0x74, 0x6d, 0x85, + 0x93, 0x89, 0x8a, 0x8c, 0x8b, 0x8c, 0x95, 0x93, 0x8f, 0x94, 0x91, + 0x8e, 0x89, 0x88, 0x84, 0x7d, 0x7d, 0x7c, 0x7e, 0x79, 0x75, 0x72, + 0x69, 0x64, 0x65, 0x69, 0x69, 0x6a, 0x70, 0x76, 0x74, 0x84, 0x95, + 0x84, 0x81, 0x92, 0x91, 0x86, 0x8c, 0x99, 0x95, 0x91, 0x91, 0x8b, + 0x89, 0x8b, 0x8a, 0x83, 0x7c, 0x7a, 0x79, 0x7a, 0x7a, 0x77, 0x71, + 0x6d, 0x69, 0x60, 0x60, 0x6e, 0x73, 0x6c, 0x6d, 0x74, 0x7b, 0x8b, + 0x90, 0x85, 0x88, 0x93, 0x90, 0x88, 0x8e, 0x98, 0x95, 0x92, 0x8f, + 0x89, 0x89, 0x8b, 0x87, 0x7f, 0x7d, 0x7c, 0x7b, 0x78, 0x79, 0x77, + 0x72, 0x70, 0x6d, 0x67, 0x64, 0x6f, 0x70, 0x6b, 0x70, 0x71, 0x79, + 0x78, 0x86, 0x9c, 0x94, 0x89, 0x8a, 0x8f, 0x8b, 0x8d, 0x95, 0x95, + 0x92, 0x8f, 0x89, 0x83, 0x86, 0x86, 0x83, 0x7e, 0x7a, 0x79, 0x78, + 0x78, 0x74, 0x79, 0x7c, 0x70, 0x64, 0x65, 0x6d, 0x6e, 0x6c, 0x75, + 0x7b, 0x6c, 0x6d, 0x7a, 0x8c, 0x9c, 0x8f, 0x8b, 0x92, 0x93, 0x88, + 0x86, 0x96, 0x99, 0x90, 0x8e, 0x8d, 0x88, 0x80, 0x80, 0x82, 0x82, + 0x7d, 0x78, 0x79, 0x7e, 0x78, 0x72, 0x78, 0x79, 0x71, 0x6c, 0x6f, + 0x71, 0x70, 0x6b, 0x6c, 0x75, 0x79, 0x72, 0x6e, 0x78, 0x84, 0x93, + 0x95, 0x89, 0x8e, 0x98, 0x91, 0x86, 0x8f, 0x98, 0x90, 0x8b, 0x8d, + 0x8a, 0x84, 0x83, 0x82, 0x80, 0x80, 0x80, 0x7a, 0x78, 0x7b, 0x79, + 0x72, 0x74, 0x79, 0x75, 0x70, 0x73, 0x74, 0x6f, 0x6f, 0x73, 0x6f, + 0x70, 0x74, 0x79, 0x74, 0x73, 0x80, 0x8a, 0x97, 0x97, 0x8c, 0x8a, + 0x91, 0x91, 0x89, 0x8c, 0x92, 0x92, 0x8e, 0x8a, 0x87, 0x81, 0x80, + 0x80, 0x81, 0x7f, 0x7c, 0x80, 0x7c, 0x78, 0x77, 0x7a, 0x76, 0x71, + 0x79, 0x78, 0x74, 0x74, 0x77, 0x75, 0x73, 0x71, 0x71, 0x78, 0x77, + 0x76, 0x7a, 0x7d, 0x73, 0x71, 0x86, 0x9a, 0x94, 0x8e, 0x99, 0x94, + 0x88, 0x85, 0x90, 0x90, 0x88, 0x8f, 0x90, 0x8c, 0x84, 0x83, 0x82, + 0x7f, 0x7f, 0x7b, 0x79, 0x7b, 0x7e, 0x7b, 0x7a, 0x7b, 0x76, 0x74, + 0x75, 0x78, 0x76, 0x75, 0x76, 0x79, 0x7a, 0x75, 0x6e, 0x70, 0x77, + 0x78, 0x72, 0x77, 0x82, 0x7e, 0x76, 0x7a, 0x7c, 0x7b, 0x91, 0x9e, + 0x90, 0x8f, 0x98, 0x8e, 0x7f, 0x89, 0x91, 0x8b, 0x8b, 0x8e, 0x8c, + 0x84, 0x84, 0x85, 0x7f, 0x7c, 0x7e, 0x7e, 0x7c, 0x7c, 0x7c, 0x7a, + 0x77, 0x75, 0x78, 0x7c, 0x77, 0x76, 0x79, 0x78, 0x75, 0x78, 0x7e, + 0x7a, 0x76, 0x76, 0x7a, 0x78, 0x72, 0x75, 0x7e, 0x7e, 0x79, 0x7c, + 0x7e, 0x7b, 0x76, 0x77, 0x80, 0x92, 0x9a, 0x92, 0x92, 0x94, 0x8f, + 0x88, 0x89, 0x8c, 0x8a, 0x8e, 0x8e, 0x89, 0x85, 0x84, 0x81, 0x7d, + 0x7d, 0x7e, 0x7d, 0x7c, 0x7b, 0x7a, 0x79, 0x78, 0x77, 0x78, 0x7a, + 0x7a, 0x7e, 0x79, 0x76, 0x7a, 0x78, 0x72, 0x74, 0x82, 0x7d, 0x72, + 0x76, 0x7d, 0x77, 0x6e, 0x78, 0x7f, 0x7b, 0x78, 0x7d, 0x7f, 0x79, + 0x77, 0x7a, 0x80, 0x8b, 0x97, 0x98, 0x94, 0x94, 0x91, 0x8b, 0x87, + 0x8a, 0x8c, 0x8a, 0x8c, 0x8c, 0x8a, 0x84, 0x81, 0x81, 0x7f, 0x7c, + 0x7c, 0x7c, 0x7a, 0x7b, 0x7b, 0x7b, 0x7a, 0x76, 0x79, 0x7a, 0x7c, + 0x7a, 0x79, 0x79, 0x77, 0x76, 0x76, 0x78, 0x7a, 0x7a, 0x77, 0x76, + 0x76, 0x73, 0x75, 0x7a, 0x79, 0x75, 0x7c, 0x7e, 0x78, 0x76, 0x79, + 0x7b, 0x81, 0x8e, 0x96, 0x99, 0x96, 0x93, 0x90, 0x8b, 0x87, 0x88, + 0x8f, 0x8e, 0x8c, 0x8a, 0x89, 0x86, 0x80, 0x7f, 0x80, 0x7e, 0x7c, + 0x7a, 0x7b, 0x79, 0x79, 0x79, 0x76, 0x77, 0x78, 0x78, 0x79, 0x7a, + 0x7b, 0x7a, 0x7c, 0x7d, 0x7e, 0x7f, 0x85, 0x83, 0x7b, 0x7e, 0x80, + 0x7a, 0x76, 0x7e, 0x80, 0x79, 0x78, 0x7b, 0x78, 0x73, 0x75, 0x77, + 0x77, 0x77, 0x78, 0x7a, 0x7b, 0x79, 0x79, 0x82, 0x8e, 0x92, 0x91, + 0x95, 0x98, 0x90, 0x89, 0x8b, 0x8b, 0x87, 0x87, 0x8a, 0x88, 0x85, + 0x83, 0x81, 0x80, 0x7e, 0x7b, 0x7a, 0x7b, 0x79, 0x77, 0x78, 0x77, + 0x78, 0x76, 0x77, 0x77, 0x77, 0x79, 0x79, 0x7a, 0x7b, 0x7d, 0x7d, + 0x7c, 0x7e, 0x7f, 0x7e, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x82, 0x81, + 0x82, 0x81, 0x82, 0x80, 0x84, 0x88, 0x82, 0x82, 0x85, 0x83, 0x7c, + 0x7e, 0x82, 0x7d, 0x7e, 0x7f, 0x80, 0x7c, 0x7c, 0x7e, 0x7c, 0x7c, + 0x7c, 0x7e, 0x7d, 0x7d, 0x7d, 0x7d, 0x7e, 0x7d, 0x7d, 0x7f, 0x80, + 0x7c, 0x7b, 0x7e, 0x7c, 0x7a, 0x7b, 0x7f, 0x7f, 0x7f, 0x81, 0x80, + 0x83, 0x85, 0x84, 0x83, 0x85, 0x87, 0x83, 0x86, 0x88, 0x85, 0x83, + 0x84, 0x85, 0x80, 0x80, 0x80, 0x80, 0x7c, 0x7c, 0x7f, 0x7c, 0x7a, + 0x7b, 0x7c, 0x7a, 0x78, 0x7a, 0x7a, 0x78, 0x78, 0x7a, 0x7a, 0x78, + 0x7a, 0x7b, 0x7c, 0x7a, 0x7c, 0x7e, 0x7d, 0x7d, 0x7e, 0x80, 0x7f, + 0x7e, 0x81, 0x81, 0x7f, 0x80, 0x83, 0x81, 0x80, 0x82, 0x83, 0x81, + 0x81, 0x83, 0x82, 0x80, 0x82, 0x82, 0x81, 0x81, 0x82, 0x81, 0x80, + 0x81, 0x81, 0x7f, 0x80, 0x81, 0x80, 0x7e, 0x7f, 0x7f, 0x7f, 0x7d, + 0x7e, 0x7e, 0x7d, 0x7e, 0x7e, 0x7e, 0x7d, 0x7e, 0x7d, 0x7d, 0x7e, + 0x7d, 0x7e, 0x7d, 0x7f, 0x7e, 0x7d, 0x7e, 0x7f, 0x7f, 0x7e, 0x7f, + 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x7f, + 0x81, 0x80, 0x7e, 0x80, 0x81, 0x7e, 0x7e, 0x80, 0x7e, 0x7d, 0x7e, + 0x7f, 0x7e, 0x7d, 0x7e, 0x7d, 0x7d, 0x7e, 0x7d, 0x7c, 0x7d, 0x7e, + 0x7d, 0x7e, 0x7f, 0x7e, 0x7f, 0x80, 0x80, 0x7f, 0x81, 0x81, 0x80, + 0x81, 0x82, 0x81, 0x80, 0x81, 0x82, 0x81, 0x81, 0x82, 0x81, 0x80, + 0x81, 0x80, 0x80, 0x81, 0x7f, 0x7e, 0x7f, 0x7f, 0x7d, 0x7d, 0x7e, + 0x7d, 0x7c, 0x7d, 0x7e, 0x7d, 0x7c, 0x7d, 0x7d, 0x7e, 0x7d, 0x7c, + 0x7d, 0x7e, 0x7d, 0x7d, 0x7e, 0x7d, 0x7e, 0x7f, 0x7e, 0x7f, 0x7f, + 0x7f, 0x80, 0x81, 0x80, 0x81, 0x80, 0x81, 0x80, 0x80, 0x80, 0x81, + 0x80, 0x81, 0x80, 0x81, 0x80, 0x81, 0x80, 0x80, 0x7f, 0x80, 0x7f, + 0x7f, 0x7f, 0x7e, 0x7e, 0x7f, 0x7e, 0x7f, 0x7e, 0x7f, 0x7e, 0x7e, + 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x7e, 0x7e, 0x7f, + 0x7e, 0x7f, 0x7e, 0x7f, 0x7f, 0x7e, 0x7f, 0x80, 0x7f, 0x80, 0x7f, + 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, + 0x7f, 0x80, 0x7f, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, 0x7f, 0x7e, + 0x7f, 0x7e, 0x7f, 0x7e, 0x7f, 0x7e, 0x7f, 0x7e, 0x7f, 0x7e, 0x7f, + 0x7e, 0x7f, 0x7e, 0x7f, 0x7e, 0x7f, 0x7f, 0x7e, 0x80, 0x7f, 0x7f, + 0x7e, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x7f, + 0x7e, 0x7f, 0x7f, 0x7e, 0x7f, 0x7f, 0x7e, 0x7e, 0x7f, 0x7e, 0x7f, + 0x7f, 0x7e, 0x7f, 0x7f, 0x7e, 0x7f, 0x7f, 0x7e, 0x7e, 0x7f, 0x7e, + 0x7f, 0x7f, 0x7e, 0x7f, 0x7e, 0x7f, 0x7e, 0x7f, 0x7e, 0x7f, 0x7f, + 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x7e, 0x7f, 0x80, 0x7e, 0x7f, + 0x7f, 0x7f, 0x7e, 0x7f, 0x7f, 0x7e, 0x80, 0x7f, 0x7f, 0x7f, 0x7e, + 0x7f, 0x7f, 0x7f, 0x7e, 0x7f, 0x7f, 0x7e, 0x7f, 0x7e, 0x7f, 0x7e, + 0x7f, 0x7f, 0x7f, 0x7e, 0x7f, 0x7f, 0x7e, 0x7f, 0x7f, 0x7e, 0x7f, + 0x7e, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x7e, 0x7f, 0x7f, 0x7e, 0x7f, + 0x7e, 0x7f, 0x7e, 0x7f, 0x7e, 0x7f, 0x7f, 0x7e, 0x7f, 0x80, 0x7f, + 0x7f, 0x80, 0x7f, 0x7e, 0x7f, 0x7e, 0x7f, 0x7e, 0x7f, 0x7e, 0x7f, + 0x7f, 0x7f, 0x7e, 0x7f, 0x7f, 0x7e, 0x7f, 0x7e, 0x7f, 0x7e, 0x7f, + 0x7e, 0x7f, 0x7f, 0x7e, 0x7f, 0x7f, 0x7f, 0x7e, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7e, 0x7f, 0x7e, 0x7f, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7e, 0x7f, 0x7f, 0x7e, 0x7f, 0x7f, 0x7e, 0x7f, 0x7f, 0x7e, 0x7f, + 0x7e, 0x7f, 0x7e, 0x7f, 0x7f, 0x7e, 0x7f, 0x7e, 0x7f, 0x7e, 0x7f, + 0x7e, 0x7f, 0x7f, 0x7e, 0x7f, 0x7f, 0x7e, 0x7f, 0x7f, 0x80, 0x7f, + 0x7f, 0x80, 0x7f, 0x7e, 0x7f, 0x7f, 0x7e, 0x7f, 0x7f, 0x7f, 0x7e, + 0x7e, 0x7f, 0x7f, 0x7e, 0x7f, 0x7f, 0x7f, 0x7e, 0x7f, 0x7f, 0x7e, + 0x7f, 0x7e, 0x7f, 0x7e, 0x7f, 0x7e, 0x7f, 0x7e, 0x7f, 0x7e, 0x7f, + 0x7e, 0x7f, 0x7e, 0x7f, 0x7e, 0x7f, 0x7f, 0x7f, 0x7e, 0x7f, 0x7f, + 0x7e, 0x7f, 0x7f, 0x7f, 0x7e, 0x7f, 0x80, 0x7f, 0x7e, 0x7f, 0x7e, + 0x7f, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7e, 0x7f, 0x7e, 0x7f, 0x7e, 0x7f, 0x7e, 0x7f, 0x7e, 0x7f, 0x7e, + 0x7f, 0x7e, 0x7f, 0x7e, 0x7f, 0x7f, 0x7f, 0x7e, 0x7f, 0x7e, 0x7f, + 0x7e, 0x7f, 0x7e, 0x7f, 0x7e, 0x7f, 0x7e, 0x7f, 0x7e, 0x7f, 0x7e, + 0x7f, 0x7e, 0x7f, 0x7f, 0x7e, 0x7f, 0x7e, 0x7f, 0x7f, 0x7e, 0x7f, + 0x7e, 0x7f, 0x7e, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x7e, 0x7f, 0x80, + 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, 0x7f, 0x7e, + 0x7f, 0x7f, 0x7e, 0x7f, 0x7e, 0x7f, 0x7f, 0x7e, 0x7f, 0x7f, 0x80, + 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, 0x7f, 0x80, + 0x80, 0x7f, 0x80, 0x7f, + }, + { // 3 + 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x80, + 0x80, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, + 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x80, + 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, + 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, + 0x80, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x7f, + 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x80, + 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x7f, + 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, + 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, + 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x7f, + 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x80, 0x80, + 0x80, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x80, + 0x81, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x81, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x7f, + 0x81, 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x7f, + 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x7e, 0x7e, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x81, 0x80, 0x7f, 0x7f, 0x80, + 0x80, 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x7f, + 0x80, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x81, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, + 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x81, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x7f, 0x80, 0x81, 0x7f, 0x7f, 0x80, 0x81, 0x80, + 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, + 0x81, 0x81, 0x80, 0x7f, 0x7f, 0x81, 0x80, 0x81, 0x80, 0x80, 0x7f, + 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x80, + 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x81, 0x81, 0x80, 0x7f, 0x7f, 0x7f, + 0x7f, 0x80, 0x7f, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, 0x80, 0x7f, + 0x80, 0x7e, 0x7e, 0x80, 0x7f, 0x7f, 0x7f, 0x81, 0x80, 0x7e, 0x7e, + 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x7e, 0x7e, 0x7f, 0x7f, 0x80, + 0x7f, 0x80, 0x7f, 0x80, 0x82, 0x82, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7e, 0x7f, 0x7f, 0x7f, 0x80, 0x7e, 0x80, 0x7f, + 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x7e, 0x80, 0x7f, 0x80, 0x80, + 0x7f, 0x81, 0x80, 0x80, 0x7e, 0x7e, 0x80, 0x80, 0x7e, 0x7f, 0x7f, + 0x7f, 0x7d, 0x7d, 0x80, 0x80, 0x7e, 0x7e, 0x80, 0x80, 0x81, 0x80, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x80, 0x81, 0x80, 0x7f, 0x7f, 0x7e, + 0x80, 0x80, 0x82, 0x81, 0x80, 0x80, 0x80, 0x81, 0x7f, 0x80, 0x80, + 0x7f, 0x7e, 0x7e, 0x80, 0x80, 0x80, 0x7f, 0x81, 0x7f, 0x80, 0x7f, + 0x81, 0x80, 0x7e, 0x7d, 0x7f, 0x80, 0x81, 0x82, 0x81, 0x80, 0x80, + 0x82, 0x83, 0x81, 0x80, 0x82, 0x80, 0x81, 0x7f, 0x80, 0x80, 0x7f, + 0x7f, 0x80, 0x80, 0x7e, 0x7c, 0x7d, 0x7d, 0x7b, 0x7c, 0x7e, 0x7c, + 0x7c, 0x7c, 0x7d, 0x7c, 0x7c, 0x7f, 0x7e, 0x7c, 0x7c, 0x7f, 0x7e, + 0x7f, 0x7e, 0x80, 0x7f, 0x80, 0x81, 0x81, 0x80, 0x80, 0x81, 0x80, + 0x80, 0x81, 0x83, 0x83, 0x83, 0x82, 0x81, 0x81, 0x82, 0x83, 0x83, + 0x81, 0x81, 0x80, 0x80, 0x80, 0x81, 0x82, 0x81, 0x81, 0x81, 0x80, + 0x80, 0x81, 0x82, 0x82, 0x82, 0x80, 0x80, 0x81, 0x81, 0x80, 0x80, + 0x82, 0x80, 0x7e, 0x7f, 0x82, 0x80, 0x81, 0x82, 0x82, 0x81, 0x80, + 0x82, 0x82, 0x81, 0x81, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, + 0x80, 0x7f, 0x80, 0x81, 0x81, 0x80, 0x7f, 0x80, 0x82, 0x7f, 0x7f, + 0x82, 0x82, 0x7f, 0x7e, 0x81, 0x82, 0x7f, 0x7f, 0x81, 0x81, 0x7f, + 0x7e, 0x7f, 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x81, 0x81, + 0x81, 0x81, 0x7f, 0x7e, 0x81, 0x80, 0x7e, 0x7e, 0x80, 0x80, 0x7e, + 0x7f, 0x81, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x82, 0x81, 0x7e, 0x7e, + 0x80, 0x7f, 0x7f, 0x81, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x81, 0x82, + 0x81, 0x80, 0x80, 0x7f, 0x7f, 0x81, 0x81, 0x80, 0x7f, 0x7f, 0x7e, + 0x7f, 0x7e, 0x7f, 0x80, 0x80, 0x7e, 0x7d, 0x80, 0x81, 0x7f, 0x80, + 0x81, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x81, 0x7f, 0x7f, 0x7f, + 0x7e, 0x7f, 0x80, 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x7d, 0x7e, 0x7f, + 0x80, 0x7f, 0x7e, 0x7e, 0x7e, 0x7d, 0x80, 0x80, 0x7e, 0x7f, 0x7f, + 0x7d, 0x7d, 0x7e, 0x7f, 0x7e, 0x7f, 0x80, 0x7d, 0x7d, 0x7e, 0x7f, + 0x7e, 0x7e, 0x80, 0x7e, 0x7d, 0x7e, 0x7f, 0x80, 0x80, 0x7e, 0x7e, + 0x80, 0x80, 0x7d, 0x7e, 0x80, 0x7f, 0x7d, 0x7e, 0x80, 0x7f, 0x7e, + 0x80, 0x7e, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x7e, 0x7f, 0x7f, 0x81, + 0x80, 0x7e, 0x7e, 0x7f, 0x7e, 0x7d, 0x7f, 0x7f, 0x80, 0x7f, 0x80, + 0x7d, 0x7d, 0x7f, 0x80, 0x7f, 0x7e, 0x7e, 0x7e, 0x7d, 0x7f, 0x7f, + 0x7d, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x7e, + 0x80, 0x81, 0x7f, 0x7d, 0x7f, 0x7f, 0x7e, 0x80, 0x7f, 0x7f, 0x80, + 0x7e, 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x82, 0x81, 0x7f, 0x7f, 0x80, + 0x80, 0x80, 0x80, 0x82, 0x81, 0x80, 0x7e, 0x81, 0x80, 0x7f, 0x81, + 0x7f, 0x7d, 0x7f, 0x7f, 0x7f, 0x82, 0x7f, 0x7f, 0x80, 0x80, 0x7f, + 0x7f, 0x7e, 0x80, 0x7e, 0x7f, 0x7d, 0x7d, 0x80, 0x7f, 0x7f, 0x80, + 0x80, 0x7e, 0x80, 0x7f, 0x7f, 0x7e, 0x80, 0x7f, 0x81, 0x7e, 0x7e, + 0x7f, 0x7e, 0x7e, 0x7e, 0x7f, 0x80, 0x7e, 0x7e, 0x7e, 0x7d, 0x7f, + 0x7f, 0x80, 0x7e, 0x7d, 0x7e, 0x7e, 0x7e, 0x7e, 0x7d, 0x7e, 0x7f, + 0x80, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x81, 0x7f, 0x7f, + 0x80, 0x80, 0x80, 0x81, 0x82, 0x80, 0x7e, 0x80, 0x83, 0x80, 0x81, + 0x80, 0x80, 0x80, 0x7f, 0x80, 0x81, 0x81, 0x81, 0x82, 0x80, 0x83, + 0x7f, 0x82, 0x82, 0x82, 0x81, 0x80, 0x7f, 0x80, 0x80, 0x7e, 0x80, + 0x80, 0x7e, 0x7f, 0x7e, 0x7f, 0x82, 0x80, 0x80, 0x82, 0x82, 0x81, + 0x80, 0x80, 0x80, 0x7e, 0x7e, 0x7f, 0x80, 0x7f, 0x80, 0x81, 0x80, + 0x80, 0x80, 0x80, 0x7f, 0x80, 0x81, 0x7c, 0x7d, 0x7f, 0x7c, 0x7e, + 0x7f, 0x7f, 0x7f, 0x7e, 0x7e, 0x7f, 0x80, 0x80, 0x7e, 0x80, 0x80, + 0x7f, 0x80, 0x81, 0x80, 0x80, 0x7f, 0x7f, 0x81, 0x80, 0x81, 0x7f, + 0x80, 0x7f, 0x81, 0x81, 0x81, 0x80, 0x82, 0x7f, 0x7f, 0x82, 0x82, + 0x80, 0x7f, 0x82, 0x7f, 0x7e, 0x80, 0x80, 0x80, 0x81, 0x7e, 0x81, + 0x7f, 0x7f, 0x81, 0x80, 0x7f, 0x7d, 0x80, 0x7e, 0x7f, 0x80, 0x81, + 0x7f, 0x80, 0x81, 0x7e, 0x80, 0x7e, 0x81, 0x80, 0x81, 0x81, 0x82, + 0x81, 0x7e, 0x80, 0x7e, 0x7e, 0x7e, 0x81, 0x80, 0x81, 0x80, 0x80, + 0x81, 0x7e, 0x80, 0x81, 0x80, 0x80, 0x7f, 0x7f, 0x7e, 0x80, 0x7f, + 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x7e, 0x7f, 0x7d, 0x7f, 0x81, + 0x80, 0x80, 0x81, 0x82, 0x81, 0x81, 0x7f, 0x7e, 0x80, 0x80, 0x7e, + 0x80, 0x80, 0x7f, 0x7f, 0x7d, 0x7f, 0x7f, 0x7d, 0x7c, 0x80, 0x7f, + 0x7d, 0x7c, 0x7e, 0x7e, 0x7d, 0x80, 0x7d, 0x81, 0x7f, 0x80, 0x7f, + 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x82, 0x81, 0x7e, 0x7d, 0x82, 0x80, + 0x7f, 0x81, 0x82, 0x80, 0x7f, 0x7f, 0x81, 0x80, 0x81, 0x80, 0x82, + 0x82, 0x7e, 0x7f, 0x7f, 0x80, 0x80, 0x83, 0x81, 0x7f, 0x82, 0x81, + 0x80, 0x7f, 0x81, 0x7e, 0x7e, 0x7f, 0x81, 0x81, 0x7f, 0x7e, 0x7e, + 0x81, 0x7d, 0x80, 0x80, 0x7d, 0x7e, 0x7e, 0x7d, 0x7c, 0x7e, 0x80, + 0x7d, 0x80, 0x80, 0x80, 0x7e, 0x7a, 0x80, 0x81, 0x7c, 0x7d, 0x7f, + 0x83, 0x7f, 0x80, 0x83, 0x7f, 0x81, 0x80, 0x81, 0x80, 0x81, 0x80, + 0x82, 0x83, 0x7f, 0x80, 0x7f, 0x7f, 0x7e, 0x82, 0x83, 0x82, 0x80, + 0x80, 0x81, 0x7d, 0x7c, 0x7f, 0x82, 0x7e, 0x83, 0x7f, 0x80, 0x80, + 0x80, 0x83, 0x83, 0x84, 0x7a, 0x7f, 0x7d, 0x7f, 0x7e, 0x7d, 0x84, + 0x7c, 0x7b, 0x79, 0x7e, 0x81, 0x7c, 0x80, 0x7f, 0x81, 0x81, 0x7d, + 0x7f, 0x7d, 0x7f, 0x7c, 0x7a, 0x7e, 0x7d, 0x7b, 0x7d, 0x7e, 0x80, + 0x7e, 0x7d, 0x7e, 0x7f, 0x81, 0x7f, 0x7f, 0x81, 0x81, 0x83, 0x83, + 0x81, 0x87, 0x84, 0x84, 0x80, 0x83, 0x83, 0x7e, 0x83, 0x86, 0x86, + 0x84, 0x87, 0x89, 0x87, 0x86, 0x82, 0x7c, 0x80, 0x7f, 0x7b, 0x7e, + 0x83, 0x80, 0x7f, 0x7d, 0x7f, 0x82, 0x80, 0x7b, 0x79, 0x7d, 0x7c, + 0x76, 0x78, 0x7d, 0x7e, 0x7c, 0x79, 0x7e, 0x7b, 0x7c, 0x7c, 0x7f, + 0x7f, 0x7a, 0x7b, 0x7e, 0x7d, 0x7a, 0x7f, 0x7b, 0x7c, 0x7b, 0x7c, + 0x7c, 0x79, 0x7b, 0x7d, 0x79, 0x78, 0x7a, 0x7c, 0x7b, 0x7d, 0x80, + 0x82, 0x86, 0x84, 0x89, 0x8c, 0x92, 0x93, 0x95, 0x97, 0x98, 0x97, + 0x92, 0x92, 0x8f, 0x85, 0x7b, 0x70, 0x62, 0x60, 0x64, 0x65, 0x5d, + 0x5d, 0x5d, 0x5e, 0x60, 0x73, 0x92, 0xa5, 0xab, 0xaa, 0xad, 0xae, + 0xa4, 0x96, 0x93, 0x9a, 0x9a, 0x92, 0x8c, 0x85, 0x7d, 0x6c, 0x60, + 0x56, 0x4d, 0x45, 0x4b, 0x4a, 0x4c, 0x4f, 0x62, 0x9a, 0xa9, 0xa5, + 0xa2, 0x9c, 0x98, 0x80, 0x78, 0x84, 0x92, 0x98, 0x98, 0x9c, 0x9d, + 0x8f, 0x79, 0x79, 0x6f, 0x5a, 0x56, 0x51, 0x4a, 0x4e, 0x56, 0x70, + 0x7b, 0x83, 0xb0, 0xae, 0xa4, 0x94, 0x85, 0x8c, 0x82, 0x82, 0x91, + 0xa2, 0xa9, 0xa6, 0x9e, 0x98, 0x8a, 0x79, 0x72, 0x72, 0x71, 0x65, + 0x59, 0x53, 0x4a, 0x4e, 0x5c, 0x77, 0x75, 0x86, 0xb4, 0xa5, 0x99, + 0x84, 0x7e, 0x83, 0x7c, 0x88, 0x98, 0xad, 0xab, 0x9b, 0x95, 0x85, + 0x78, 0x6e, 0x6f, 0x78, 0x6e, 0x5e, 0x54, 0x50, 0x45, 0x4c, 0x62, + 0x86, 0x71, 0x9c, 0xbc, 0xa0, 0x92, 0x74, 0x88, 0x7d, 0x83, 0x93, + 0xa8, 0xb9, 0xa5, 0x96, 0x8d, 0x7c, 0x73, 0x73, 0x7b, 0x7b, 0x68, + 0x60, 0x5a, 0x49, 0x45, 0x54, 0x7f, 0x82, 0x75, 0xbd, 0xb3, 0x96, + 0x7b, 0x71, 0x84, 0x7d, 0x89, 0xa5, 0xb9, 0xad, 0x97, 0x88, 0x7c, + 0x75, 0x71, 0x78, 0x8a, 0x74, 0x66, 0x59, 0x56, 0x49, 0x47, 0x58, + 0x8a, 0x7c, 0x8c, 0xc7, 0xa4, 0x8f, 0x6d, 0x74, 0x7c, 0x7c, 0x91, + 0xab, 0xb4, 0xa6, 0x8e, 0x7a, 0x75, 0x75, 0x73, 0x82, 0x82, 0x73, + 0x62, 0x51, 0x50, 0x49, 0x4b, 0x64, 0x90, 0x81, 0xb4, 0xb8, 0x93, + 0x81, 0x62, 0x74, 0x79, 0x8c, 0xa3, 0xb6, 0xb0, 0x9a, 0x83, 0x74, + 0x70, 0x76, 0x7b, 0x8d, 0x7e, 0x6d, 0x60, 0x56, 0x4d, 0x50, 0x52, + 0x6e, 0x96, 0x8b, 0xc0, 0xaf, 0x89, 0x70, 0x66, 0x76, 0x80, 0x94, + 0xa8, 0xb8, 0xa3, 0x8d, 0x75, 0x71, 0x75, 0x7d, 0x83, 0x8f, 0x7c, + 0x6a, 0x58, 0x58, 0x5c, 0x59, 0x4a, 0x74, 0x8f, 0x91, 0xc7, 0xa2, + 0x8c, 0x6c, 0x60, 0x76, 0x82, 0x9c, 0xb3, 0xb6, 0x9e, 0x82, 0x70, + 0x72, 0x79, 0x81, 0x8f, 0x8c, 0x75, 0x64, 0x5b, 0x5c, 0x56, 0x50, + 0x57, 0x91, 0x8e, 0xac, 0xbf, 0x8d, 0x79, 0x56, 0x66, 0x7d, 0x94, + 0xae, 0xba, 0xaa, 0x8d, 0x73, 0x6d, 0x74, 0x83, 0x8b, 0x90, 0x7f, + 0x6a, 0x5d, 0x5b, 0x5d, 0x60, 0x4e, 0x5f, 0x95, 0x8f, 0xc0, 0xad, + 0x87, 0x6d, 0x57, 0x70, 0x83, 0x9d, 0xb8, 0xb6, 0xa4, 0x83, 0x6d, + 0x6f, 0x76, 0x86, 0x89, 0x8b, 0x73, 0x67, 0x5d, 0x5c, 0x5a, 0x66, + 0x4d, 0x73, 0x91, 0xa6, 0xc8, 0x91, 0x7f, 0x67, 0x61, 0x75, 0x8d, + 0xac, 0xb5, 0xa5, 0x96, 0x76, 0x6c, 0x71, 0x82, 0x87, 0x8e, 0x84, + 0x71, 0x65, 0x5f, 0x5c, 0x5c, 0x5a, 0x50, 0x8b, 0x93, 0xc0, 0xb1, + 0x7f, 0x72, 0x5b, 0x6a, 0x7c, 0x9e, 0xb8, 0xb4, 0x9b, 0x87, 0x6e, + 0x72, 0x75, 0x87, 0x90, 0x8f, 0x79, 0x6d, 0x61, 0x60, 0x5e, 0x67, + 0x4f, 0x5e, 0x95, 0x97, 0xc5, 0x97, 0x78, 0x6e, 0x5b, 0x71, 0x88, + 0xa4, 0xb8, 0xa1, 0x96, 0x7d, 0x6e, 0x74, 0x7a, 0x8d, 0x8b, 0x8a, + 0x76, 0x6a, 0x5f, 0x5a, 0x63, 0x60, 0x4a, 0x88, 0x97, 0xaf, 0xb0, + 0x80, 0x77, 0x5e, 0x63, 0x83, 0x9c, 0xb3, 0xa9, 0x99, 0x84, 0x6b, + 0x75, 0x78, 0x8f, 0x8a, 0x84, 0x78, 0x69, 0x5e, 0x5e, 0x5f, 0x67, + 0x4c, 0x79, 0x97, 0xac, 0xbb, 0x80, 0x77, 0x64, 0x64, 0x7b, 0x97, + 0xb5, 0xa9, 0x97, 0x84, 0x70, 0x72, 0x73, 0x8e, 0x8c, 0x86, 0x74, + 0x69, 0x65, 0x5e, 0x5d, 0x63, 0x51, 0x7d, 0x96, 0xad, 0xb4, 0x7f, + 0x79, 0x61, 0x6b, 0x7e, 0x99, 0xb3, 0xaa, 0x96, 0x83, 0x70, 0x74, + 0x77, 0x89, 0x8c, 0x81, 0x76, 0x69, 0x60, 0x5e, 0x65, 0x64, 0x53, + 0x7c, 0x93, 0xa9, 0xb2, 0x81, 0x7b, 0x63, 0x69, 0x84, 0x99, 0xb3, + 0xa8, 0x99, 0x83, 0x71, 0x73, 0x7a, 0x8b, 0x8a, 0x84, 0x75, 0x66, + 0x5f, 0x5a, 0x64, 0x5e, 0x51, 0x85, 0x94, 0xab, 0xad, 0x80, 0x7b, + 0x63, 0x6e, 0x8b, 0x9c, 0xb1, 0xa2, 0x95, 0x83, 0x75, 0x78, 0x82, + 0x8a, 0x86, 0x7d, 0x71, 0x65, 0x61, 0x5d, 0x61, 0x61, 0x58, 0x8f, + 0x8d, 0xa9, 0x9e, 0x76, 0x75, 0x61, 0x83, 0x92, 0xa2, 0xaa, 0x9b, + 0x91, 0x7c, 0x7c, 0x85, 0x8b, 0x8b, 0x84, 0x7c, 0x70, 0x67, 0x64, + 0x62, 0x64, 0x52, 0x5d, 0x8d, 0x8f, 0xa8, 0x89, 0x76, 0x70, 0x67, + 0x86, 0x92, 0xa3, 0xa2, 0x9d, 0x8e, 0x80, 0x80, 0x85, 0x8e, 0x89, + 0x87, 0x80, 0x75, 0x68, 0x5f, 0x5b, 0x67, 0x51, 0x6a, 0x8e, 0x88, + 0xa5, 0x80, 0x75, 0x67, 0x69, 0x8f, 0x95, 0xa4, 0x9f, 0x9a, 0x8c, + 0x80, 0x80, 0x89, 0x8d, 0x8c, 0x88, 0x83, 0x72, 0x66, 0x5e, 0x5d, + 0x62, 0x51, 0x80, 0x8b, 0x8d, 0x9c, 0x7b, 0x73, 0x61, 0x71, 0x90, + 0x95, 0xa4, 0x9d, 0x99, 0x89, 0x7e, 0x82, 0x89, 0x8d, 0x89, 0x8a, + 0x80, 0x70, 0x66, 0x62, 0x60, 0x61, 0x56, 0x87, 0x83, 0x95, 0x9b, + 0x78, 0x70, 0x5e, 0x7f, 0x8e, 0x98, 0xa0, 0x9d, 0x97, 0x84, 0x81, + 0x83, 0x8a, 0x90, 0x8c, 0x8b, 0x7b, 0x6e, 0x68, 0x5d, 0x5f, 0x58, + 0x5e, 0x89, 0x7c, 0x9a, 0x93, 0x78, 0x6f, 0x63, 0x82, 0x8c, 0x98, + 0x9f, 0xa0, 0x95, 0x85, 0x81, 0x86, 0x89, 0x89, 0x8e, 0x8b, 0x7c, + 0x6a, 0x66, 0x5f, 0x5f, 0x53, 0x64, 0x93, 0x7c, 0x9b, 0x8a, 0x7c, + 0x6b, 0x5e, 0x8a, 0x8a, 0x9c, 0x9e, 0xa0, 0x96, 0x81, 0x7f, 0x84, + 0x8b, 0x89, 0x8a, 0x8c, 0x7c, 0x68, 0x62, 0x5b, 0x63, 0x50, 0x72, + 0x8a, 0x84, 0xa0, 0x82, 0x7c, 0x69, 0x6e, 0x8a, 0x8e, 0x9d, 0xa1, + 0x9f, 0x91, 0x81, 0x82, 0x84, 0x88, 0x8c, 0x8e, 0x86, 0x77, 0x69, + 0x60, 0x59, 0x60, 0x59, 0x79, 0x82, 0x81, 0xa0, 0x7f, 0x79, 0x64, + 0x78, 0x8a, 0x89, 0x9d, 0xa1, 0x9f, 0x90, 0x85, 0x84, 0x84, 0x86, + 0x8c, 0x8d, 0x87, 0x75, 0x6b, 0x62, 0x5a, 0x59, 0x55, 0x7d, 0x7e, + 0x82, 0x9a, 0x81, 0x79, 0x64, 0x77, 0x86, 0x89, 0x9d, 0xa4, 0xa2, + 0x91, 0x83, 0x83, 0x84, 0x87, 0x8d, 0x91, 0x88, 0x77, 0x6b, 0x5e, + 0x58, 0x55, 0x5a, 0x7e, 0x76, 0x8a, 0x9b, 0x80, 0x77, 0x66, 0x7d, + 0x80, 0x8c, 0x9d, 0xa8, 0xa1, 0x91, 0x87, 0x85, 0x84, 0x84, 0x8f, + 0x8f, 0x83, 0x74, 0x6c, 0x60, 0x57, 0x51, 0x63, 0x81, 0x71, 0x8d, + 0x96, 0x80, 0x78, 0x69, 0x81, 0x7f, 0x8f, 0x9f, 0xa5, 0x9e, 0x8d, + 0x89, 0x88, 0x83, 0x85, 0x93, 0x8e, 0x80, 0x72, 0x6b, 0x5f, 0x58, + 0x53, 0x69, 0x7b, 0x70, 0x8a, 0x90, 0x82, 0x76, 0x6d, 0x82, 0x80, + 0x89, 0x9c, 0xa6, 0x9e, 0x91, 0x8b, 0x8a, 0x82, 0x86, 0x8f, 0x8e, + 0x83, 0x72, 0x6c, 0x5e, 0x55, 0x52, 0x6e, 0x74, 0x70, 0x8e, 0x8c, + 0x7f, 0x72, 0x73, 0x7e, 0x7e, 0x8a, 0xa2, 0xa7, 0x9c, 0x96, 0x8e, + 0x8a, 0x80, 0x86, 0x91, 0x8a, 0x80, 0x74, 0x6b, 0x5e, 0x53, 0x57, + 0x72, 0x6f, 0x70, 0x8d, 0x8b, 0x80, 0x72, 0x7b, 0x83, 0x7f, 0x8e, + 0x9f, 0xa4, 0x9b, 0x94, 0x8f, 0x8b, 0x82, 0x87, 0x8f, 0x88, 0x7d, + 0x73, 0x6a, 0x5d, 0x53, 0x5d, 0x71, 0x69, 0x72, 0x8d, 0x86, 0x7e, + 0x76, 0x7e, 0x83, 0x7e, 0x8c, 0x9f, 0xa2, 0x9b, 0x97, 0x95, 0x8e, + 0x82, 0x89, 0x8b, 0x83, 0x7b, 0x76, 0x6a, 0x5c, 0x54, 0x62, 0x6c, + 0x60, 0x77, 0x8a, 0x83, 0x7b, 0x79, 0x84, 0x82, 0x80, 0x91, 0x9f, + 0x9e, 0x98, 0x99, 0x99, 0x8c, 0x85, 0x8c, 0x8a, 0x81, 0x78, 0x73, + 0x69, 0x5a, 0x57, 0x65, 0x69, 0x66, 0x7a, 0x83, 0x81, 0x7a, 0x7c, + 0x83, 0x81, 0x85, 0x91, 0x9d, 0x9b, 0x97, 0x99, 0x97, 0x8d, 0x8a, + 0x8d, 0x89, 0x80, 0x76, 0x71, 0x68, 0x5d, 0x5f, 0x67, 0x68, 0x66, + 0x74, 0x7b, 0x7a, 0x79, 0x7e, 0x86, 0x83, 0x87, 0x91, 0x98, 0x98, + 0x97, 0x99, 0x98, 0x90, 0x8e, 0x8d, 0x8a, 0x83, 0x7b, 0x75, 0x6d, + 0x65, 0x65, 0x67, 0x65, 0x66, 0x6f, 0x72, 0x72, 0x74, 0x7c, 0x81, + 0x83, 0x88, 0x8f, 0x93, 0x93, 0x95, 0x97, 0x99, 0x94, 0x93, 0x92, + 0x8e, 0x89, 0x82, 0x7e, 0x77, 0x70, 0x6c, 0x6b, 0x65, 0x63, 0x66, + 0x67, 0x68, 0x6b, 0x71, 0x77, 0x7c, 0x81, 0x88, 0x8e, 0x92, 0x95, + 0x99, 0x9c, 0x9b, 0x9d, 0x9a, 0x99, 0x94, 0x8e, 0x87, 0x81, 0x78, + 0x71, 0x6b, 0x63, 0x60, 0x5d, 0x5d, 0x5f, 0x62, 0x67, 0x6c, 0x74, + 0x7b, 0x83, 0x8a, 0x91, 0x97, 0x9c, 0x9f, 0xa2, 0xa2, 0xa0, 0x9e, + 0x9a, 0x93, 0x8c, 0x86, 0x7c, 0x73, 0x6d, 0x66, 0x5f, 0x5b, 0x5c, + 0x5c, 0x5e, 0x61, 0x68, 0x6e, 0x75, 0x7e, 0x85, 0x8e, 0x95, 0x99, + 0x9e, 0xa2, 0xa2, 0xa1, 0xa1, 0x9e, 0x98, 0x92, 0x8a, 0x82, 0x78, + 0x70, 0x69, 0x62, 0x5c, 0x5b, 0x5c, 0x5c, 0x5f, 0x64, 0x6b, 0x72, + 0x7a, 0x82, 0x8a, 0x91, 0x96, 0x9b, 0xa0, 0xa2, 0xa2, 0xa1, 0xa0, + 0x9b, 0x95, 0x8f, 0x86, 0x7d, 0x73, 0x6c, 0x64, 0x5e, 0x5b, 0x5c, + 0x5b, 0x5d, 0x62, 0x68, 0x6f, 0x76, 0x7e, 0x86, 0x8e, 0x93, 0x98, + 0x9d, 0xa1, 0xa2, 0xa2, 0xa1, 0x9d, 0x97, 0x91, 0x89, 0x81, 0x77, + 0x6f, 0x68, 0x62, 0x5d, 0x5d, 0x5d, 0x5d, 0x61, 0x66, 0x6c, 0x73, + 0x7b, 0x83, 0x8a, 0x91, 0x96, 0x9b, 0x9f, 0xa1, 0xa1, 0xa1, 0x9e, + 0x99, 0x94, 0x8c, 0x84, 0x7b, 0x73, 0x6c, 0x64, 0x5f, 0x5d, 0x5d, + 0x5d, 0x60, 0x65, 0x6b, 0x71, 0x78, 0x80, 0x88, 0x8e, 0x93, 0x98, + 0x9d, 0x9f, 0xa0, 0xa1, 0x9f, 0x9b, 0x96, 0x90, 0x88, 0x7f, 0x76, + 0x70, 0x69, 0x62, 0x5f, 0x5e, 0x5d, 0x5e, 0x62, 0x67, 0x6d, 0x73, + 0x7b, 0x83, 0x89, 0x8f, 0x95, 0x9a, 0x9d, 0x9f, 0x9f, 0xa0, 0x9d, + 0x98, 0x93, 0x8d, 0x84, 0x7b, 0x74, 0x6e, 0x67, 0x61, 0x60, 0x5f, + 0x5e, 0x61, 0x65, 0x6b, 0x70, 0x77, 0x7f, 0x86, 0x8c, 0x91, 0x97, + 0x9b, 0x9d, 0x9e, 0x9f, 0x9e, 0x9b, 0x95, 0x90, 0x89, 0x80, 0x77, + 0x72, 0x6b, 0x64, 0x61, 0x60, 0x5f, 0x60, 0x64, 0x69, 0x6f, 0x74, + 0x7b, 0x82, 0x89, 0x8f, 0x93, 0x98, 0x9b, 0x9d, 0x9d, 0x9d, 0x9b, + 0x96, 0x91, 0x8b, 0x83, 0x7a, 0x74, 0x6e, 0x67, 0x63, 0x61, 0x61, + 0x60, 0x63, 0x68, 0x6d, 0x72, 0x79, 0x80, 0x86, 0x8c, 0x91, 0x96, + 0x9a, 0x9b, 0x9c, 0x9d, 0x9b, 0x97, 0x93, 0x8d, 0x85, 0x7d, 0x76, + 0x70, 0x6a, 0x65, 0x63, 0x62, 0x62, 0x64, 0x68, 0x6c, 0x71, 0x78, + 0x7e, 0x85, 0x8a, 0x8f, 0x94, 0x98, 0x9a, 0x9b, 0x9c, 0x9b, 0x97, + 0x93, 0x8d, 0x87, 0x7f, 0x77, 0x72, 0x6c, 0x66, 0x64, 0x64, 0x63, + 0x64, 0x68, 0x6d, 0x71, 0x77, 0x7e, 0x84, 0x89, 0x8e, 0x93, 0x96, + 0x99, 0x9a, 0x9b, 0x9a, 0x97, 0x93, 0x8e, 0x88, 0x80, 0x79, 0x73, + 0x6d, 0x68, 0x65, 0x65, 0x63, 0x64, 0x68, 0x6d, 0x71, 0x76, 0x7d, + 0x83, 0x88, 0x8c, 0x92, 0x95, 0x97, 0x99, 0x9a, 0x9a, 0x96, 0x93, + 0x8e, 0x87, 0x80, 0x79, 0x74, 0x6e, 0x69, 0x66, 0x66, 0x64, 0x65, + 0x69, 0x6d, 0x72, 0x77, 0x7d, 0x83, 0x88, 0x8d, 0x92, 0x95, 0x97, + 0x98, 0x99, 0x98, 0x95, 0x92, 0x8c, 0x86, 0x7e, 0x78, 0x73, 0x6d, + 0x69, 0x67, 0x66, 0x65, 0x67, 0x6b, 0x6f, 0x73, 0x79, 0x7f, 0x84, + 0x89, 0x8d, 0x92, 0x95, 0x96, 0x98, 0x98, 0x97, 0x94, 0x90, 0x8b, + 0x85, 0x7e, 0x78, 0x73, 0x6e, 0x69, 0x67, 0x67, 0x66, 0x67, 0x6b, + 0x6f, 0x73, 0x78, 0x7e, 0x84, 0x88, 0x8c, 0x90, 0x94, 0x96, 0x97, + 0x98, 0x97, 0x94, 0x90, 0x8b, 0x86, 0x7f, 0x79, 0x75, 0x70, 0x6b, + 0x68, 0x68, 0x67, 0x68, 0x6c, 0x70, 0x73, 0x78, 0x7d, 0x82, 0x87, + 0x8b, 0x90, 0x92, 0x94, 0x96, 0x96, 0x96, 0x93, 0x90, 0x8b, 0x86, + 0x7f, 0x79, 0x75, 0x70, 0x6c, 0x6a, 0x69, 0x69, 0x6a, 0x6d, 0x71, + 0x74, 0x79, 0x7e, 0x82, 0x87, 0x8b, 0x8f, 0x91, 0x93, 0x95, 0x95, + 0x94, 0x92, 0x8f, 0x8a, 0x85, 0x7e, 0x79, 0x75, 0x70, 0x6d, 0x6a, + 0x6a, 0x69, 0x6a, 0x6e, 0x71, 0x75, 0x79, 0x7f, 0x83, 0x87, 0x8b, + 0x8f, 0x91, 0x93, 0x94, 0x95, 0x94, 0x91, 0x8d, 0x89, 0x84, 0x7d, + 0x79, 0x74, 0x70, 0x6d, 0x6b, 0x6b, 0x6a, 0x6c, 0x6f, 0x73, 0x76, + 0x7b, 0x80, 0x84, 0x88, 0x8b, 0x8f, 0x91, 0x92, 0x93, 0x94, 0x93, + 0x90, 0x8c, 0x88, 0x82, 0x7d, 0x79, 0x74, 0x70, 0x6d, 0x6b, 0x6b, + 0x6b, 0x6d, 0x70, 0x73, 0x77, 0x7b, 0x80, 0x84, 0x88, 0x8c, 0x8f, + 0x90, 0x92, 0x93, 0x93, 0x91, 0x8f, 0x8b, 0x87, 0x81, 0x7c, 0x78, + 0x74, 0x70, 0x6e, 0x6d, 0x6c, 0x6c, 0x6e, 0x71, 0x74, 0x78, 0x7c, + 0x81, 0x85, 0x88, 0x8c, 0x8f, 0x91, 0x91, 0x92, 0x92, 0x90, 0x8d, + 0x89, 0x85, 0x7f, 0x7b, 0x77, 0x73, 0x70, 0x6e, 0x6d, 0x6d, 0x6e, + 0x70, 0x73, 0x76, 0x79, 0x7e, 0x82, 0x85, 0x89, 0x8c, 0x8e, 0x90, + 0x91, 0x91, 0x91, 0x8e, 0x8c, 0x88, 0x83, 0x7e, 0x7b, 0x77, 0x74, + 0x70, 0x6f, 0x6e, 0x6e, 0x6f, 0x72, 0x75, 0x77, 0x7b, 0x7f, 0x83, + 0x86, 0x8a, 0x8c, 0x8e, 0x8f, 0x90, 0x91, 0x8f, 0x8d, 0x89, 0x86, + 0x81, 0x7d, 0x79, 0x76, 0x72, 0x70, 0x6f, 0x6f, 0x70, 0x71, 0x74, + 0x76, 0x79, 0x7d, 0x81, 0x85, 0x88, 0x8a, 0x8d, 0x8e, 0x8f, 0x90, + 0x8f, 0x8e, 0x8a, 0x87, 0x83, 0x7e, 0x7b, 0x77, 0x74, 0x72, 0x70, + 0x70, 0x70, 0x71, 0x73, 0x75, 0x78, 0x7c, 0x7f, 0x83, 0x86, 0x89, + 0x8b, 0x8d, 0x8e, 0x8f, 0x8f, 0x8d, 0x8b, 0x88, 0x84, 0x80, 0x7d, + 0x79, 0x76, 0x73, 0x71, 0x71, 0x70, 0x71, 0x73, 0x75, 0x77, 0x7b, + 0x7e, 0x82, 0x85, 0x88, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x8e, 0x8c, + 0x89, 0x86, 0x82, 0x7e, 0x7b, 0x78, 0x75, 0x72, 0x71, 0x71, 0x71, + 0x72, 0x74, 0x76, 0x78, 0x7c, 0x7f, 0x82, 0x85, 0x88, 0x8b, 0x8c, + 0x8d, 0x8e, 0x8e, 0x8d, 0x8a, 0x87, 0x84, 0x80, 0x7d, 0x7a, 0x77, + 0x74, 0x72, 0x71, 0x71, 0x72, 0x74, 0x76, 0x77, 0x7a, 0x7d, 0x81, + 0x84, 0x87, 0x89, 0x8b, 0x8c, 0x8d, 0x8d, 0x8c, 0x8b, 0x88, 0x85, + 0x82, 0x7f, 0x7c, 0x79, 0x76, 0x74, 0x73, 0x72, 0x72, 0x74, 0x75, + 0x76, 0x79, 0x7c, 0x7f, 0x82, 0x85, 0x87, 0x89, 0x8a, 0x8c, 0x8c, + 0x8c, 0x8b, 0x89, 0x87, 0x84, 0x81, 0x7e, 0x7b, 0x79, 0x76, 0x74, + 0x73, 0x73, 0x74, 0x75, 0x76, 0x78, 0x7a, 0x7d, 0x80, 0x83, 0x86, + 0x87, 0x89, 0x8a, 0x8b, 0x8c, 0x8b, 0x8a, 0x88, 0x85, 0x83, 0x80, + 0x7e, 0x7b, 0x78, 0x76, 0x75, 0x74, 0x74, 0x75, 0x77, 0x78, 0x7a, + 0x7c, 0x7f, 0x81, 0x83, 0x85, 0x87, 0x88, 0x89, 0x89, 0x88, 0x87, + 0x86, 0x84, 0x82, 0x80, 0x7e, 0x7c, 0x7a, 0x78, 0x77, 0x77, 0x77, + 0x78, 0x79, 0x7a, 0x7c, 0x7e, 0x80, 0x82, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x88, 0x88, 0x87, 0x85, 0x84, 0x82, 0x81, 0x7e, 0x7c, 0x7a, + 0x78, 0x77, 0x77, 0x77, 0x77, 0x78, 0x79, 0x7a, 0x7c, 0x7e, 0x80, + 0x82, 0x84, 0x85, 0x86, 0x87, 0x87, 0x87, 0x86, 0x86, 0x85, 0x83, + 0x82, 0x80, 0x7e, 0x7c, 0x7a, 0x79, 0x79, 0x78, 0x78, 0x78, 0x79, + 0x7a, 0x7c, 0x7d, 0x7f, 0x80, 0x82, 0x83, 0x84, 0x85, 0x86, 0x86, + 0x86, 0x85, 0x85, 0x84, 0x83, 0x82, 0x80, 0x7e, 0x7d, 0x7c, 0x7b, + 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x80, 0x81, + 0x82, 0x83, 0x84, 0x84, 0x85, 0x85, 0x84, 0x84, 0x83, 0x82, 0x81, + 0x80, 0x7f, 0x7e, 0x7d, 0x7c, 0x7c, 0x7b, 0x7b, 0x7b, 0x7b, 0x7c, + 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x82, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x82, 0x82, 0x81, 0x81, 0x80, 0x7f, 0x7f, 0x7e, 0x7d, + 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7e, 0x7e, 0x7f, 0x7f, 0x80, + 0x80, 0x81, 0x81, 0x82, 0x82, 0x82, 0x82, 0x82, 0x81, 0x81, 0x81, + 0x80, 0x80, 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, + 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, + 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x7f, + 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x80, + 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, + 0x7f, 0x80, + }, + { // 4 + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x80, + 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, + 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, + 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, + 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, + 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, + 0x80, 0x7f, 0x7f, 0x7f, 0x7e, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x80, + 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x80, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x80, + 0x7f, 0x81, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7e, 0x7f, 0x7e, 0x7e, + 0x7f, 0x7f, 0x80, 0x7f, 0x7e, 0x7f, 0x7f, 0x7f, 0x81, 0x80, 0x80, + 0x7f, 0x80, 0x80, 0x80, 0x80, 0x81, 0x80, 0x80, 0x7f, 0x81, 0x80, + 0x80, 0x81, 0x80, 0x80, 0x80, 0x80, 0x81, 0x81, 0x81, 0x82, 0x81, + 0x81, 0x81, 0x81, 0x80, 0x81, 0x81, 0x82, 0x81, 0x82, 0x82, 0x81, + 0x80, 0x81, 0x82, 0x82, 0x81, 0x82, 0x81, 0x81, 0x80, 0x80, 0x82, + 0x82, 0x80, 0x81, 0x80, 0x81, 0x81, 0x81, 0x82, 0x81, 0x80, 0x80, + 0x80, 0x81, 0x81, 0x81, 0x81, 0x81, 0x80, 0x7f, 0x80, 0x81, 0x80, + 0x80, 0x81, 0x82, 0x83, 0x82, 0x81, 0x82, 0x81, 0x80, 0x80, 0x7f, + 0x7f, 0x7f, 0x7e, 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7e, 0x7e, + 0x7e, 0x7f, 0x7f, 0x7d, 0x7d, 0x7e, 0x7d, 0x7e, 0x7e, 0x7e, 0x7f, + 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x81, + 0x81, 0x80, 0x80, 0x7f, 0x7e, 0x7e, 0x7f, 0x7d, 0x7e, 0x7f, 0x80, + 0x80, 0x80, 0x81, 0x81, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x80, + 0x7f, 0x7f, 0x7e, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x7e, 0x7d, 0x7f, + 0x7e, 0x7e, 0x7d, 0x7c, 0x7c, 0x7c, 0x7c, 0x7e, 0x7f, 0x7d, 0x7e, + 0x7e, 0x7d, 0x7d, 0x7d, 0x7e, 0x7f, 0x7d, 0x7d, 0x7d, 0x7d, 0x7c, + 0x7d, 0x7c, 0x7c, 0x7d, 0x7d, 0x7d, 0x7e, 0x7e, 0x7f, 0x7f, 0x7e, + 0x7f, 0x7d, 0x7d, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7e, 0x7c, 0x7e, + 0x80, 0x80, 0x7e, 0x7d, 0x7e, 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x80, + 0x7f, 0x7d, 0x81, 0x80, 0x7f, 0x7f, 0x7f, 0x80, 0x7e, 0x7e, 0x7e, + 0x7f, 0x7f, 0x80, 0x80, 0x7d, 0x7d, 0x80, 0x7f, 0x7f, 0x7d, 0x7e, + 0x7e, 0x7d, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x7d, 0x7e, 0x7f, 0x81, + 0x7f, 0x7d, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x80, 0x7e, 0x7e, + 0x7e, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x7d, 0x7d, 0x7f, 0x7f, 0x7e, + 0x80, 0x81, 0x7f, 0x81, 0x7e, 0x80, 0x7f, 0x81, 0x81, 0x7f, 0x7f, + 0x7e, 0x81, 0x7f, 0x81, 0x81, 0x80, 0x80, 0x81, 0x84, 0x80, 0x7f, + 0x80, 0x7e, 0x7e, 0x80, 0x82, 0x80, 0x7f, 0x81, 0x81, 0x7f, 0x7e, + 0x80, 0x7f, 0x81, 0x81, 0x7e, 0x7f, 0x80, 0x81, 0x81, 0x80, 0x7e, + 0x81, 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x7e, 0x80, 0x7e, 0x7f, 0x7f, + 0x80, 0x7e, 0x7d, 0x80, 0x7f, 0x80, 0x81, 0x80, 0x80, 0x7e, 0x7f, + 0x7e, 0x81, 0x80, 0x7d, 0x7f, 0x80, 0x80, 0x7c, 0x7d, 0x7b, 0x7b, + 0x7d, 0x7c, 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, 0x7d, 0x7f, 0x81, 0x7f, + 0x7e, 0x7c, 0x7e, 0x7d, 0x7d, 0x80, 0x81, 0x7e, 0x7f, 0x80, 0x80, + 0x83, 0x85, 0x81, 0x83, 0x84, 0x83, 0x7f, 0x80, 0x80, 0x81, 0x84, + 0x7f, 0x7f, 0x7f, 0x82, 0x7f, 0x7f, 0x7f, 0x7c, 0x81, 0x80, 0x7e, + 0x7d, 0x7f, 0x7f, 0x81, 0x82, 0x81, 0x80, 0x7e, 0x7c, 0x7d, 0x80, + 0x81, 0x80, 0x7f, 0x82, 0x7e, 0x80, 0x80, 0x80, 0x81, 0x82, 0x7f, + 0x7d, 0x7e, 0x7e, 0x80, 0x80, 0x7b, 0x7b, 0x7f, 0x81, 0x82, 0x7f, + 0x7e, 0x7e, 0x80, 0x80, 0x80, 0x80, 0x82, 0x7e, 0x7a, 0x80, 0x82, + 0x81, 0x81, 0x83, 0x83, 0x80, 0x7f, 0x7f, 0x7f, 0x81, 0x83, 0x85, + 0x86, 0x81, 0x7b, 0x7c, 0x7e, 0x80, 0x82, 0x83, 0x80, 0x81, 0x80, + 0x7f, 0x83, 0x81, 0x7e, 0x7d, 0x7d, 0x7d, 0x7d, 0x7a, 0x7d, 0x80, + 0x7e, 0x7c, 0x7e, 0x82, 0x7e, 0x7c, 0x80, 0x7f, 0x7c, 0x7d, 0x7e, + 0x7e, 0x7c, 0x7a, 0x7d, 0x80, 0x7e, 0x7f, 0x80, 0x7f, 0x7f, 0x82, + 0x83, 0x82, 0x7f, 0x80, 0x81, 0x83, 0x80, 0x81, 0x82, 0x81, 0x81, + 0x7f, 0x80, 0x7c, 0x81, 0x81, 0x80, 0x81, 0x81, 0x7f, 0x7f, 0x82, + 0x7f, 0x82, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x81, 0x80, 0x7d, + 0x7f, 0x7e, 0x7c, 0x7c, 0x7d, 0x80, 0x7e, 0x7d, 0x7e, 0x7e, 0x7e, + 0x7d, 0x81, 0x82, 0x7d, 0x79, 0x7c, 0x7f, 0x7b, 0x7d, 0x7d, 0x7f, + 0x7d, 0x7e, 0x7e, 0x7d, 0x7f, 0x7f, 0x81, 0x80, 0x7e, 0x7d, 0x82, + 0x82, 0x7e, 0x7e, 0x83, 0x7e, 0x7d, 0x81, 0x7f, 0x7e, 0x7e, 0x80, + 0x7d, 0x7d, 0x7d, 0x7e, 0x7e, 0x80, 0x81, 0x81, 0x82, 0x7b, 0x79, + 0x81, 0x81, 0x80, 0x7f, 0x82, 0x7f, 0x7c, 0x7e, 0x81, 0x7e, 0x7e, + 0x80, 0x7f, 0x7e, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7e, + 0x7d, 0x7d, 0x7f, 0x80, 0x82, 0x82, 0x7c, 0x77, 0x7d, 0x7f, 0x7d, + 0x7f, 0x7e, 0x7d, 0x7e, 0x7f, 0x7f, 0x7d, 0x7c, 0x80, 0x7f, 0x7c, + 0x7b, 0x7c, 0x7e, 0x7d, 0x7d, 0x81, 0x80, 0x7d, 0x7d, 0x7f, 0x81, + 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x82, 0x81, 0x7e, 0x81, 0x83, 0x80, + 0x80, 0x7e, 0x81, 0x80, 0x7f, 0x80, 0x7f, 0x7b, 0x7c, 0x81, 0x82, + 0x7f, 0x7e, 0x7e, 0x7f, 0x7c, 0x7c, 0x7e, 0x7e, 0x81, 0x7d, 0x7e, + 0x7e, 0x81, 0x82, 0x7f, 0x7c, 0x80, 0x82, 0x80, 0x7f, 0x80, 0x80, + 0x83, 0x83, 0x81, 0x7f, 0x7e, 0x83, 0x82, 0x7f, 0x7f, 0x80, 0x7f, + 0x80, 0x83, 0x84, 0x82, 0x82, 0x81, 0x81, 0x80, 0x81, 0x81, 0x7f, + 0x7d, 0x7d, 0x82, 0x82, 0x7c, 0x7e, 0x7e, 0x7c, 0x7e, 0x7f, 0x7d, + 0x7c, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x7e, 0x7b, 0x7d, 0x7f, 0x7e, + 0x80, 0x80, 0x80, 0x7d, 0x7d, 0x81, 0x80, 0x7f, 0x80, 0x82, 0x82, + 0x7f, 0x80, 0x83, 0x83, 0x80, 0x81, 0x82, 0x7e, 0x7f, 0x7e, 0x7d, + 0x7d, 0x7c, 0x7e, 0x7f, 0x7c, 0x7e, 0x80, 0x81, 0x81, 0x83, 0x84, + 0x83, 0x83, 0x82, 0x82, 0x80, 0x81, 0x82, 0x82, 0x80, 0x7b, 0x79, + 0x7a, 0x7b, 0x7d, 0x7e, 0x7e, 0x7c, 0x7b, 0x7f, 0x82, 0x7f, 0x7f, + 0x84, 0x87, 0x86, 0x87, 0x84, 0x84, 0x84, 0x80, 0x7d, 0x7a, 0x77, + 0x75, 0x74, 0x6f, 0x6c, 0x6e, 0x74, 0x76, 0x7c, 0x85, 0x8b, 0x8f, + 0x97, 0x9d, 0xa1, 0xa3, 0xa0, 0x9a, 0x8d, 0x80, 0x75, 0x6c, 0x68, + 0x61, 0x56, 0x53, 0x5c, 0x63, 0x68, 0x6f, 0x7b, 0x88, 0x91, 0x96, + 0xa3, 0xb3, 0xb6, 0xb5, 0xb1, 0xa9, 0x96, 0x7e, 0x6c, 0x5f, 0x58, + 0x54, 0x51, 0x51, 0x50, 0x54, 0x5f, 0x6a, 0x74, 0x7e, 0x89, 0x92, + 0x99, 0x9d, 0xa3, 0xaa, 0xa9, 0xa6, 0xa1, 0x9b, 0x98, 0x93, 0x90, + 0x8c, 0x88, 0x82, 0x78, 0x6c, 0x5f, 0x58, 0x52, 0x4c, 0x4e, 0x52, + 0x57, 0x5d, 0x67, 0x75, 0x81, 0x8b, 0x94, 0x9b, 0xa3, 0xa7, 0xaa, + 0xad, 0xac, 0xa6, 0xa3, 0x9d, 0x98, 0x93, 0x8c, 0x87, 0x7f, 0x75, + 0x6a, 0x5e, 0x53, 0x4b, 0x45, 0x4b, 0x50, 0x59, 0x5d, 0x69, 0x77, + 0x82, 0x8f, 0x96, 0xa0, 0xa5, 0xa9, 0xac, 0xac, 0xab, 0xa6, 0xa0, + 0x9b, 0x95, 0x90, 0x89, 0x81, 0x78, 0x6c, 0x61, 0x55, 0x4f, 0x45, + 0x41, 0x47, 0x50, 0x5e, 0x63, 0x71, 0x7e, 0x8d, 0x95, 0x9e, 0xa8, + 0xad, 0xaf, 0xad, 0xaf, 0xab, 0xa5, 0x9e, 0x9a, 0x92, 0x89, 0x7f, + 0x77, 0x69, 0x60, 0x56, 0x4e, 0x44, 0x3a, 0x45, 0x4d, 0x5d, 0x60, + 0x71, 0x82, 0x8f, 0x98, 0x9e, 0xa9, 0xad, 0xae, 0xaf, 0xaf, 0xab, + 0xa6, 0x9f, 0x9b, 0x91, 0x88, 0x7c, 0x76, 0x66, 0x5d, 0x53, 0x4d, + 0x41, 0x39, 0x42, 0x4e, 0x5e, 0x61, 0x73, 0x85, 0x95, 0x9a, 0xa0, + 0xad, 0xb2, 0xb2, 0xaf, 0xb1, 0xad, 0xa4, 0x9e, 0x96, 0x8c, 0x7f, + 0x78, 0x6d, 0x5f, 0x53, 0x4c, 0x45, 0x38, 0x3c, 0x4a, 0x5f, 0x61, + 0x6c, 0x80, 0x93, 0x9b, 0x9d, 0xab, 0xb3, 0xb4, 0xb0, 0xb1, 0xb0, + 0xa7, 0x9e, 0x97, 0x8b, 0x7f, 0x77, 0x6e, 0x62, 0x55, 0x50, 0x4b, + 0x3b, 0x3a, 0x49, 0x5c, 0x63, 0x69, 0x80, 0x92, 0x9b, 0x9c, 0xa8, + 0xb3, 0xb7, 0xb2, 0xb1, 0xaf, 0xa8, 0xa1, 0x93, 0x87, 0x7d, 0x75, + 0x6b, 0x5f, 0x55, 0x52, 0x47, 0x38, 0x3c, 0x50, 0x60, 0x63, 0x6c, + 0x83, 0x96, 0x9a, 0x9d, 0xa9, 0xb4, 0xb6, 0xb1, 0xae, 0xad, 0xa8, + 0x9d, 0x8d, 0x81, 0x7c, 0x73, 0x64, 0x59, 0x56, 0x53, 0x44, 0x36, + 0x43, 0x5a, 0x63, 0x64, 0x73, 0x8e, 0x9c, 0x9b, 0x9e, 0xb0, 0xb9, + 0xb4, 0xad, 0xad, 0xae, 0xa2, 0x92, 0x85, 0x7e, 0x75, 0x67, 0x5d, + 0x5c, 0x59, 0x4b, 0x39, 0x3c, 0x55, 0x5f, 0x61, 0x6b, 0x86, 0x97, + 0x96, 0x9a, 0xab, 0xb9, 0xb5, 0xac, 0xaf, 0xaf, 0xa5, 0x96, 0x8c, + 0x88, 0x7b, 0x6c, 0x64, 0x62, 0x5e, 0x53, 0x47, 0x3c, 0x48, 0x57, + 0x5e, 0x65, 0x74, 0x8a, 0x93, 0x97, 0x9e, 0xae, 0xb6, 0xb2, 0xb0, + 0xb0, 0xac, 0x9d, 0x94, 0x8b, 0x82, 0x75, 0x6b, 0x68, 0x65, 0x5c, + 0x55, 0x4c, 0x3f, 0x4a, 0x58, 0x62, 0x65, 0x72, 0x86, 0x91, 0x95, + 0x9b, 0xac, 0xb2, 0xb0, 0xad, 0xaf, 0xa9, 0x9b, 0x92, 0x8b, 0x80, + 0x73, 0x6e, 0x6b, 0x68, 0x5e, 0x59, 0x4f, 0x43, 0x4d, 0x5b, 0x62, + 0x64, 0x72, 0x85, 0x90, 0x92, 0x9c, 0xad, 0xb3, 0xb1, 0xad, 0xb0, + 0xaa, 0x9e, 0x93, 0x8c, 0x83, 0x74, 0x72, 0x6e, 0x6b, 0x64, 0x5f, + 0x54, 0x42, 0x48, 0x58, 0x5f, 0x5d, 0x68, 0x7f, 0x8b, 0x8e, 0x97, + 0xa9, 0xb4, 0xb1, 0xae, 0xaf, 0xae, 0xa2, 0x98, 0x90, 0x86, 0x7c, + 0x74, 0x74, 0x6f, 0x6c, 0x6a, 0x63, 0x4f, 0x3d, 0x4a, 0x59, 0x58, + 0x56, 0x68, 0x80, 0x86, 0x8b, 0x97, 0xb1, 0xb7, 0xb2, 0xb2, 0xb2, + 0xae, 0xa1, 0x98, 0x8d, 0x83, 0x7c, 0x78, 0x74, 0x6f, 0x70, 0x6f, + 0x62, 0x4d, 0x42, 0x50, 0x56, 0x51, 0x53, 0x66, 0x7e, 0x82, 0x88, + 0x9d, 0xb3, 0xb9, 0xb6, 0xb7, 0xb8, 0xb2, 0xa4, 0x98, 0x8f, 0x86, + 0x7f, 0x77, 0x72, 0x73, 0x75, 0x72, 0x6a, 0x5e, 0x54, 0x47, 0x49, + 0x50, 0x53, 0x59, 0x62, 0x77, 0x82, 0x8f, 0x9c, 0xaf, 0xba, 0xba, + 0xb8, 0xb6, 0xb0, 0xa4, 0x97, 0x8c, 0x83, 0x7e, 0x79, 0x73, 0x76, + 0x77, 0x75, 0x70, 0x6a, 0x5d, 0x4f, 0x46, 0x50, 0x56, 0x58, 0x59, + 0x6b, 0x83, 0x8a, 0x95, 0xa6, 0xbb, 0xbd, 0xb8, 0xb4, 0xb4, 0xac, + 0x98, 0x8b, 0x86, 0x83, 0x77, 0x71, 0x76, 0x7b, 0x75, 0x71, 0x70, + 0x71, 0x64, 0x51, 0x4a, 0x52, 0x58, 0x57, 0x5c, 0x6d, 0x84, 0x8a, + 0x95, 0xa3, 0xb8, 0xba, 0xb3, 0xb5, 0xb4, 0xa8, 0x92, 0x8b, 0x87, + 0x81, 0x75, 0x75, 0x79, 0x7a, 0x77, 0x77, 0x7b, 0x78, 0x6c, 0x60, + 0x57, 0x50, 0x4e, 0x57, 0x5a, 0x63, 0x6a, 0x7c, 0x8c, 0x99, 0xa9, + 0xb4, 0xbd, 0xba, 0xb8, 0xb1, 0xaa, 0x99, 0x8d, 0x83, 0x81, 0x7e, + 0x77, 0x76, 0x79, 0x81, 0x7e, 0x7e, 0x7e, 0x7d, 0x72, 0x61, 0x54, + 0x4b, 0x4b, 0x50, 0x50, 0x5a, 0x66, 0x79, 0x89, 0x96, 0xa7, 0xb4, + 0xbd, 0xbc, 0xb9, 0xb2, 0xa8, 0x9c, 0x92, 0x86, 0x81, 0x7d, 0x7d, + 0x7a, 0x7d, 0x83, 0x84, 0x84, 0x81, 0x82, 0x7c, 0x6f, 0x62, 0x54, + 0x4b, 0x40, 0x40, 0x4d, 0x56, 0x62, 0x6f, 0x86, 0x97, 0xa5, 0xb0, + 0xbb, 0xc1, 0xbd, 0xb6, 0xac, 0xa3, 0x96, 0x89, 0x81, 0x7c, 0x7e, + 0x7d, 0x7f, 0x82, 0x89, 0x8a, 0x87, 0x86, 0x82, 0x7c, 0x6b, 0x60, + 0x51, 0x4a, 0x3b, 0x37, 0x3a, 0x4e, 0x5a, 0x65, 0x78, 0x8e, 0xa7, + 0xac, 0xb8, 0xc0, 0xc9, 0xc0, 0xb3, 0xab, 0xa3, 0x97, 0x87, 0x81, + 0x7e, 0x7c, 0x77, 0x7b, 0x86, 0x8b, 0x8a, 0x88, 0x8a, 0x86, 0x7a, + 0x70, 0x6a, 0x64, 0x57, 0x4c, 0x48, 0x47, 0x42, 0x40, 0x49, 0x63, + 0x71, 0x80, 0x8c, 0xa4, 0xb6, 0xb8, 0xc1, 0xc6, 0xcf, 0xbf, 0xb1, + 0xa8, 0xa0, 0x90, 0x79, 0x71, 0x6a, 0x63, 0x59, 0x5b, 0x64, 0x69, + 0x6d, 0x74, 0x83, 0x8b, 0x8e, 0x8f, 0x93, 0x96, 0x91, 0x8e, 0x89, + 0x88, 0x80, 0x79, 0x76, 0x72, 0x6d, 0x66, 0x67, 0x64, 0x5f, 0x57, + 0x58, 0x54, 0x50, 0x4f, 0x5f, 0x72, 0x77, 0x80, 0x8f, 0xa6, 0xaa, + 0xaf, 0xb9, 0xc3, 0xc0, 0xb2, 0xac, 0xa7, 0x9c, 0x86, 0x7a, 0x75, + 0x6f, 0x65, 0x5f, 0x65, 0x6a, 0x6d, 0x6e, 0x79, 0x82, 0x85, 0x87, + 0x8a, 0x90, 0x8c, 0x86, 0x80, 0x7f, 0x7a, 0x73, 0x72, 0x75, 0x77, + 0x71, 0x73, 0x78, 0x7e, 0x7a, 0x79, 0x7d, 0x7c, 0x74, 0x69, 0x68, + 0x61, 0x56, 0x4f, 0x58, 0x68, 0x6e, 0x70, 0x7e, 0x94, 0xa1, 0xa5, + 0xae, 0xbd, 0xc2, 0xba, 0xb2, 0xae, 0xa6, 0x94, 0x84, 0x7c, 0x74, + 0x69, 0x5e, 0x60, 0x65, 0x68, 0x6a, 0x72, 0x7d, 0x81, 0x82, 0x86, + 0x8c, 0x8e, 0x87, 0x84, 0x83, 0x7f, 0x76, 0x6e, 0x6d, 0x6e, 0x6d, + 0x68, 0x6c, 0x74, 0x7f, 0x81, 0x84, 0x8c, 0x94, 0x95, 0x8e, 0x90, + 0x8f, 0x89, 0x79, 0x71, 0x6b, 0x63, 0x58, 0x4f, 0x4f, 0x4c, 0x52, + 0x5a, 0x6d, 0x7b, 0x89, 0x99, 0xa7, 0xb7, 0xba, 0xc0, 0xbf, 0xbe, + 0xb5, 0xa6, 0x9b, 0x8c, 0x7f, 0x6e, 0x66, 0x61, 0x5e, 0x5d, 0x5f, + 0x69, 0x6f, 0x78, 0x7e, 0x88, 0x8e, 0x8f, 0x8f, 0x8d, 0x8c, 0x84, + 0x7f, 0x78, 0x73, 0x6e, 0x67, 0x67, 0x67, 0x6b, 0x6c, 0x71, 0x79, + 0x7f, 0x84, 0x88, 0x8d, 0x90, 0x91, 0x8e, 0x8d, 0x89, 0x89, 0x86, + 0x81, 0x7f, 0x7b, 0x7d, 0x79, 0x7a, 0x79, 0x7a, 0x79, 0x76, 0x74, + 0x71, 0x71, 0x6c, 0x68, 0x62, 0x68, 0x71, 0x77, 0x7e, 0x85, 0x95, + 0x9d, 0xa1, 0xa6, 0xac, 0xb0, 0xa8, 0xa1, 0x99, 0x94, 0x88, 0x7c, + 0x73, 0x6e, 0x6b, 0x65, 0x66, 0x6a, 0x70, 0x73, 0x77, 0x80, 0x86, + 0x88, 0x87, 0x89, 0x89, 0x84, 0x7f, 0x7b, 0x79, 0x72, 0x6e, 0x6c, + 0x6e, 0x6f, 0x6f, 0x72, 0x77, 0x7d, 0x7f, 0x83, 0x88, 0x8b, 0x8b, + 0x8a, 0x8b, 0x8a, 0x86, 0x81, 0x7f, 0x7c, 0x7a, 0x77, 0x76, 0x78, + 0x78, 0x7b, 0x7c, 0x80, 0x83, 0x85, 0x87, 0x8a, 0x8c, 0x8b, 0x89, + 0x88, 0x87, 0x84, 0x81, 0x7e, 0x7e, 0x7c, 0x7b, 0x7b, 0x7c, 0x7c, + 0x7d, 0x7d, 0x80, 0x81, 0x82, 0x82, 0x82, 0x84, 0x82, 0x81, 0x7f, + 0x7f, 0x7e, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7d, 0x7d, 0x7f, 0x80, + 0x89, 0x8f, 0x8d, 0x88, 0x85, 0x85, 0x7b, 0x73, 0x6d, 0x6d, 0x65, + 0x5d, 0x5c, 0x66, 0x6f, 0x71, 0x7b, 0x86, 0x96, 0x99, 0x9d, 0xa2, + 0xa6, 0xa4, 0x98, 0x93, 0x8e, 0x86, 0x78, 0x70, 0x6f, 0x6e, 0x6c, + 0x6a, 0x71, 0x79, 0x7d, 0x80, 0x86, 0x8e, 0x8e, 0x8c, 0x8a, 0x8a, + 0x86, 0x7e, 0x79, 0x76, 0x74, 0x6f, 0x6d, 0x6f, 0x73, 0x75, 0x76, + 0x7c, 0x82, 0x86, 0x87, 0x89, 0x8c, 0x8c, 0x89, 0x86, 0x85, 0x82, + 0x7e, 0x79, 0x78, 0x78, 0x77, 0x76, 0x77, 0x7b, 0x7e, 0x7f, 0x82, + 0x85, 0x88, 0x87, 0x87, 0x87, 0x87, 0x84, 0x81, 0x7f, 0x7e, 0x7d, + 0x7a, 0x7a, 0x7b, 0x7c, 0x7c, 0x7d, 0x80, 0x82, 0x83, 0x83, 0x84, + 0x84, 0x83, 0x82, 0x80, 0x80, 0x7e, 0x7d, 0x7c, 0x7c, 0x7c, 0x7b, + 0x7c, 0x7d, 0x7f, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x82, 0x82, 0x82, + 0x81, 0x80, 0x7e, 0x7e, 0x7e, 0x7d, 0x7c, 0x7d, 0x7d, 0x7e, 0x7e, + 0x7f, 0x80, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, + 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x80, 0x80, 0x80, + 0x81, 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, + 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, + }, + { // 5 + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, 0x7e, + 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, + 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7c, + 0x7c, 0x7c, 0x7d, 0x7d, 0x7d, 0x7d, 0x7e, 0x7e, 0x7f, 0x7f, 0x80, + 0x80, 0x80, 0x81, 0x81, 0x81, 0x82, 0x82, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x82, 0x81, 0x80, 0x7f, 0x7e, 0x7c, 0x7b, + 0x7a, 0x78, 0x78, 0x77, 0x77, 0x77, 0x77, 0x77, 0x78, 0x78, 0x79, + 0x7b, 0x7c, 0x7d, 0x7f, 0x80, 0x81, 0x83, 0x83, 0x84, 0x85, 0x85, + 0x86, 0x86, 0x87, 0x88, 0x88, 0x89, 0x8a, 0x8a, 0x8a, 0x8a, 0x89, + 0x87, 0x84, 0x81, 0x7d, 0x79, 0x75, 0x71, 0x6f, 0x6f, 0x6f, 0x6f, + 0x6f, 0x70, 0x70, 0x71, 0x73, 0x75, 0x77, 0x79, 0x7b, 0x7d, 0x7f, + 0x81, 0x83, 0x84, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8c, 0x8d, 0x8f, + 0x90, 0x90, 0x91, 0x90, 0x8f, 0x8e, 0x8c, 0x89, 0x86, 0x83, 0x7f, + 0x7c, 0x78, 0x75, 0x72, 0x6f, 0x6e, 0x6d, 0x6e, 0x6e, 0x6f, 0x6f, + 0x6f, 0x6f, 0x6f, 0x6f, 0x70, 0x72, 0x74, 0x76, 0x79, 0x7b, 0x7e, + 0x81, 0x83, 0x86, 0x88, 0x8a, 0x8d, 0x8f, 0x91, 0x93, 0x94, 0x95, + 0x95, 0x94, 0x93, 0x91, 0x8f, 0x8c, 0x88, 0x85, 0x81, 0x7e, 0x7b, + 0x78, 0x75, 0x73, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x71, + 0x70, 0x6f, 0x6f, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x75, 0x77, 0x7a, + 0x7c, 0x7f, 0x82, 0x84, 0x87, 0x8a, 0x8d, 0x90, 0x92, 0x95, 0x96, + 0x97, 0x97, 0x97, 0x95, 0x93, 0x90, 0x8c, 0x89, 0x85, 0x80, 0x7d, + 0x79, 0x76, 0x74, 0x73, 0x72, 0x73, 0x73, 0x73, 0x72, 0x71, 0x70, + 0x6f, 0x6e, 0x6e, 0x6e, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x74, 0x76, + 0x79, 0x7c, 0x7e, 0x81, 0x85, 0x88, 0x8b, 0x8f, 0x92, 0x95, 0x98, + 0x99, 0x9a, 0x9a, 0x99, 0x97, 0x94, 0x90, 0x8c, 0x87, 0x83, 0x7e, + 0x7a, 0x77, 0x75, 0x74, 0x73, 0x74, 0x74, 0x74, 0x73, 0x71, 0x70, + 0x6f, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6f, 0x70, 0x71, 0x73, + 0x75, 0x78, 0x7a, 0x7d, 0x80, 0x84, 0x87, 0x8b, 0x8e, 0x92, 0x96, + 0x99, 0x9b, 0x9c, 0x9d, 0x9c, 0x9a, 0x97, 0x93, 0x8e, 0x89, 0x84, + 0x7f, 0x7a, 0x77, 0x75, 0x75, 0x75, 0x75, 0x75, 0x74, 0x72, 0x70, + 0x6f, 0x6e, 0x6e, 0x6e, 0x6e, 0x6d, 0x6d, 0x6d, 0x6d, 0x6e, 0x70, + 0x71, 0x73, 0x75, 0x78, 0x7b, 0x7e, 0x81, 0x84, 0x88, 0x8c, 0x90, + 0x94, 0x98, 0x9b, 0x9d, 0x9f, 0x9f, 0x9d, 0x9b, 0x97, 0x93, 0x8d, + 0x87, 0x81, 0x7c, 0x78, 0x76, 0x76, 0x76, 0x76, 0x75, 0x74, 0x72, + 0x70, 0x6f, 0x6f, 0x6f, 0x6e, 0x6e, 0x6d, 0x6c, 0x6c, 0x6c, 0x6c, + 0x6d, 0x6e, 0x70, 0x73, 0x75, 0x78, 0x7b, 0x7e, 0x81, 0x84, 0x88, + 0x8c, 0x90, 0x95, 0x99, 0x9c, 0x9f, 0xa0, 0xa1, 0x9f, 0x9d, 0x98, + 0x93, 0x8c, 0x86, 0x80, 0x7b, 0x78, 0x78, 0x77, 0x77, 0x76, 0x74, + 0x73, 0x71, 0x70, 0x70, 0x70, 0x6f, 0x6e, 0x6d, 0x6c, 0x6b, 0x6b, + 0x6b, 0x6b, 0x6c, 0x6d, 0x6f, 0x71, 0x74, 0x77, 0x7a, 0x7d, 0x80, + 0x84, 0x87, 0x8b, 0x8f, 0x94, 0x98, 0x9d, 0xa0, 0xa2, 0xa4, 0xa3, + 0xa0, 0x9c, 0x96, 0x8f, 0x88, 0x81, 0x7d, 0x7a, 0x79, 0x78, 0x78, + 0x76, 0x74, 0x72, 0x71, 0x70, 0x70, 0x6f, 0x6e, 0x6d, 0x6c, 0x6b, + 0x6a, 0x69, 0x69, 0x69, 0x69, 0x6b, 0x6d, 0x6f, 0x72, 0x76, 0x79, + 0x7c, 0x7f, 0x82, 0x85, 0x89, 0x8d, 0x92, 0x97, 0x9c, 0xa1, 0xa5, + 0xa7, 0xa7, 0xa5, 0xa0, 0x9a, 0x93, 0x8c, 0x84, 0x7f, 0x7b, 0x7a, + 0x7a, 0x78, 0x76, 0x73, 0x71, 0x70, 0x70, 0x70, 0x70, 0x6f, 0x6e, + 0x6c, 0x6b, 0x69, 0x68, 0x67, 0x67, 0x67, 0x68, 0x6a, 0x6d, 0x70, + 0x74, 0x78, 0x7a, 0x7e, 0x80, 0x83, 0x87, 0x8c, 0x90, 0x96, 0x9d, + 0xa3, 0xa7, 0xaa, 0xaa, 0xa8, 0xa3, 0x9d, 0x95, 0x8d, 0x85, 0x7e, + 0x7b, 0x7a, 0x79, 0x78, 0x76, 0x73, 0x71, 0x70, 0x71, 0x71, 0x71, + 0x71, 0x70, 0x6e, 0x6c, 0x6a, 0x67, 0x66, 0x66, 0x66, 0x67, 0x69, + 0x6b, 0x6f, 0x72, 0x75, 0x78, 0x7b, 0x7e, 0x81, 0x84, 0x89, 0x8f, + 0x95, 0x9c, 0xa3, 0xa9, 0xac, 0xad, 0xac, 0xa7, 0xa0, 0x98, 0x8f, + 0x86, 0x7f, 0x7b, 0x79, 0x78, 0x77, 0x75, 0x72, 0x70, 0x70, 0x70, + 0x72, 0x73, 0x74, 0x73, 0x71, 0x6e, 0x6a, 0x67, 0x65, 0x64, 0x65, + 0x66, 0x68, 0x6b, 0x6e, 0x71, 0x75, 0x78, 0x7a, 0x7d, 0x7f, 0x82, + 0x86, 0x8c, 0x93, 0x9b, 0xa2, 0xa9, 0xad, 0xaf, 0xae, 0xa9, 0xa2, + 0x9a, 0x91, 0x88, 0x80, 0x7b, 0x78, 0x77, 0x76, 0x74, 0x72, 0x70, + 0x6f, 0x71, 0x73, 0x76, 0x78, 0x77, 0x75, 0x70, 0x6c, 0x68, 0x65, + 0x64, 0x64, 0x64, 0x66, 0x68, 0x6b, 0x6e, 0x72, 0x75, 0x78, 0x7a, + 0x7d, 0x80, 0x85, 0x8a, 0x92, 0x9a, 0xa3, 0xaa, 0xaf, 0xb1, 0xb0, + 0xac, 0xa5, 0x9c, 0x92, 0x89, 0x81, 0x7b, 0x77, 0x75, 0x74, 0x73, + 0x71, 0x70, 0x6f, 0x71, 0x74, 0x78, 0x7a, 0x7b, 0x78, 0x73, 0x6d, + 0x68, 0x65, 0x64, 0x63, 0x64, 0x65, 0x68, 0x6b, 0x6e, 0x71, 0x73, + 0x76, 0x79, 0x7b, 0x7f, 0x83, 0x89, 0x90, 0x99, 0xa2, 0xaa, 0xb0, + 0xb3, 0xb2, 0xae, 0xa7, 0x9f, 0x95, 0x8c, 0x83, 0x7b, 0x76, 0x72, + 0x70, 0x6f, 0x6e, 0x6e, 0x6f, 0x72, 0x76, 0x7a, 0x7d, 0x7f, 0x7d, + 0x78, 0x71, 0x6b, 0x66, 0x64, 0x63, 0x63, 0x64, 0x66, 0x69, 0x6c, + 0x6f, 0x72, 0x75, 0x78, 0x7b, 0x7e, 0x82, 0x87, 0x8e, 0x97, 0xa0, + 0xa8, 0xae, 0xb2, 0xb2, 0xaf, 0xa9, 0xa2, 0x98, 0x8f, 0x85, 0x7d, + 0x76, 0x71, 0x6e, 0x6c, 0x6b, 0x6b, 0x6e, 0x71, 0x76, 0x7b, 0x80, + 0x82, 0x81, 0x7d, 0x76, 0x6d, 0x67, 0x63, 0x62, 0x63, 0x64, 0x65, + 0x67, 0x69, 0x6d, 0x70, 0x74, 0x78, 0x7c, 0x7f, 0x83, 0x88, 0x8e, + 0x95, 0x9d, 0xa5, 0xac, 0xb0, 0xb1, 0xb0, 0xab, 0xa3, 0x9a, 0x91, + 0x87, 0x7e, 0x76, 0x71, 0x6c, 0x6a, 0x69, 0x6a, 0x6d, 0x71, 0x77, + 0x7c, 0x81, 0x84, 0x84, 0x80, 0x79, 0x70, 0x68, 0x63, 0x61, 0x62, + 0x64, 0x66, 0x68, 0x6a, 0x6d, 0x70, 0x74, 0x78, 0x7c, 0x80, 0x84, + 0x88, 0x8e, 0x94, 0x9b, 0xa3, 0xa9, 0xae, 0xb0, 0xaf, 0xab, 0xa4, + 0x9c, 0x92, 0x88, 0x7f, 0x76, 0x70, 0x6b, 0x68, 0x68, 0x69, 0x6c, + 0x71, 0x77, 0x7e, 0x84, 0x87, 0x87, 0x83, 0x7c, 0x71, 0x68, 0x61, + 0x5f, 0x60, 0x63, 0x65, 0x66, 0x68, 0x6b, 0x6f, 0x73, 0x78, 0x7d, + 0x82, 0x86, 0x8b, 0x8f, 0x95, 0x9b, 0xa1, 0xa7, 0xac, 0xaf, 0xaf, + 0xac, 0xa6, 0x9e, 0x95, 0x8a, 0x80, 0x77, 0x70, 0x6b, 0x67, 0x66, + 0x67, 0x6b, 0x70, 0x76, 0x7d, 0x83, 0x88, 0x89, 0x86, 0x7f, 0x76, + 0x6b, 0x63, 0x5d, 0x5d, 0x60, 0x63, 0x66, 0x69, 0x6b, 0x6e, 0x72, + 0x77, 0x7c, 0x81, 0x86, 0x8a, 0x8e, 0x93, 0x98, 0x9e, 0xa3, 0xa8, + 0xac, 0xad, 0xac, 0xa8, 0xa2, 0x99, 0x90, 0x85, 0x7c, 0x73, 0x6d, + 0x69, 0x67, 0x67, 0x6a, 0x6e, 0x74, 0x7a, 0x81, 0x87, 0x8a, 0x89, + 0x85, 0x7c, 0x72, 0x67, 0x5f, 0x5a, 0x5b, 0x5e, 0x63, 0x68, 0x6c, + 0x70, 0x73, 0x77, 0x7a, 0x7e, 0x82, 0x86, 0x8b, 0x8f, 0x94, 0x9a, + 0x9f, 0xa4, 0xa7, 0xaa, 0xab, 0xa9, 0xa5, 0x9f, 0x97, 0x8e, 0x84, + 0x7b, 0x73, 0x6d, 0x69, 0x67, 0x68, 0x6b, 0x6f, 0x75, 0x7c, 0x82, + 0x87, 0x89, 0x88, 0x83, 0x7b, 0x71, 0x67, 0x60, 0x5c, 0x5c, 0x5f, + 0x63, 0x68, 0x6c, 0x70, 0x73, 0x77, 0x7c, 0x81, 0x86, 0x8a, 0x8d, + 0x91, 0x94, 0x98, 0x9c, 0xa0, 0xa3, 0xa6, 0xa7, 0xa6, 0xa2, 0x9d, + 0x95, 0x8c, 0x84, 0x7c, 0x74, 0x6e, 0x6b, 0x6a, 0x6b, 0x6e, 0x72, + 0x77, 0x7d, 0x83, 0x87, 0x88, 0x85, 0x7f, 0x77, 0x6e, 0x66, 0x60, + 0x5e, 0x60, 0x64, 0x68, 0x6c, 0x70, 0x72, 0x75, 0x78, 0x7c, 0x80, + 0x85, 0x89, 0x8d, 0x90, 0x93, 0x98, 0x9c, 0x9f, 0xa3, 0xa5, 0xa6, + 0xa5, 0xa1, 0x9b, 0x94, 0x8c, 0x83, 0x7a, 0x73, 0x6e, 0x6b, 0x6a, + 0x6c, 0x6f, 0x73, 0x78, 0x7d, 0x82, 0x85, 0x86, 0x84, 0x7e, 0x77, + 0x6f, 0x68, 0x63, 0x61, 0x62, 0x65, 0x69, 0x6c, 0x70, 0x73, 0x76, + 0x7a, 0x7e, 0x83, 0x86, 0x8a, 0x8d, 0x90, 0x94, 0x97, 0x9b, 0x9e, + 0xa1, 0xa3, 0xa3, 0xa1, 0x9d, 0x98, 0x91, 0x89, 0x81, 0x7a, 0x74, + 0x6f, 0x6d, 0x6c, 0x6d, 0x70, 0x74, 0x78, 0x7d, 0x81, 0x83, 0x84, + 0x82, 0x7f, 0x79, 0x72, 0x6b, 0x66, 0x63, 0x63, 0x66, 0x6a, 0x6e, + 0x72, 0x76, 0x79, 0x7c, 0x7e, 0x81, 0x84, 0x88, 0x8b, 0x8f, 0x92, + 0x96, 0x99, 0x9d, 0xa0, 0xa2, 0xa2, 0xa0, 0x9c, 0x97, 0x90, 0x89, + 0x82, 0x7b, 0x75, 0x71, 0x6f, 0x6e, 0x6f, 0x71, 0x74, 0x78, 0x7b, + 0x7f, 0x82, 0x83, 0x83, 0x80, 0x7c, 0x75, 0x6f, 0x69, 0x65, 0x64, + 0x65, 0x68, 0x6d, 0x71, 0x75, 0x79, 0x7c, 0x7e, 0x80, 0x83, 0x86, + 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9d, 0xa0, 0xa1, 0xa0, 0x9e, 0x99, + 0x94, 0x8e, 0x87, 0x81, 0x7b, 0x76, 0x73, 0x71, 0x70, 0x71, 0x72, + 0x74, 0x77, 0x7a, 0x7d, 0x7f, 0x81, 0x82, 0x81, 0x7e, 0x79, 0x74, + 0x6e, 0x6a, 0x67, 0x67, 0x69, 0x6d, 0x71, 0x75, 0x78, 0x7b, 0x7d, + 0x7f, 0x81, 0x84, 0x88, 0x8c, 0x90, 0x95, 0x9a, 0x9d, 0xa0, 0xa0, + 0x9f, 0x9c, 0x98, 0x92, 0x8c, 0x86, 0x80, 0x7b, 0x77, 0x74, 0x73, + 0x72, 0x73, 0x74, 0x76, 0x78, 0x7a, 0x7c, 0x7e, 0x80, 0x80, 0x80, + 0x7e, 0x7b, 0x76, 0x72, 0x6d, 0x6a, 0x6a, 0x6b, 0x6e, 0x71, 0x75, + 0x78, 0x7b, 0x7d, 0x7f, 0x81, 0x84, 0x87, 0x8b, 0x8f, 0x94, 0x98, + 0x9c, 0x9e, 0x9f, 0x9e, 0x9a, 0x96, 0x90, 0x8a, 0x84, 0x7e, 0x7a, + 0x76, 0x75, 0x74, 0x74, 0x75, 0x76, 0x77, 0x79, 0x7a, 0x7c, 0x7d, + 0x7e, 0x7f, 0x7e, 0x7d, 0x7b, 0x77, 0x74, 0x70, 0x6e, 0x6d, 0x6e, + 0x70, 0x73, 0x76, 0x79, 0x7b, 0x7d, 0x7f, 0x80, 0x82, 0x85, 0x89, + 0x8e, 0x94, 0x98, 0x9d, 0x9f, 0x9f, 0x9d, 0x98, 0x93, 0x8c, 0x86, + 0x80, 0x7b, 0x78, 0x76, 0x75, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, + 0x7b, 0x7c, 0x7c, 0x7c, 0x7c, 0x7b, 0x7a, 0x78, 0x76, 0x73, 0x71, + 0x70, 0x70, 0x71, 0x73, 0x76, 0x79, 0x7c, 0x7e, 0x80, 0x82, 0x84, + 0x86, 0x89, 0x8c, 0x90, 0x94, 0x98, 0x9a, 0x9b, 0x9a, 0x97, 0x93, + 0x8d, 0x87, 0x82, 0x7d, 0x79, 0x77, 0x76, 0x76, 0x77, 0x78, 0x7a, + 0x7b, 0x7c, 0x7c, 0x7c, 0x7c, 0x7b, 0x7a, 0x79, 0x77, 0x76, 0x74, + 0x73, 0x72, 0x72, 0x72, 0x74, 0x76, 0x78, 0x7b, 0x7d, 0x7f, 0x81, + 0x83, 0x85, 0x88, 0x8b, 0x8f, 0x92, 0x95, 0x97, 0x98, 0x98, 0x95, + 0x92, 0x8d, 0x88, 0x83, 0x7f, 0x7b, 0x79, 0x78, 0x77, 0x78, 0x79, + 0x7a, 0x7b, 0x7c, 0x7c, 0x7c, 0x7c, 0x7b, 0x7a, 0x78, 0x76, 0x75, + 0x73, 0x72, 0x72, 0x72, 0x73, 0x75, 0x77, 0x79, 0x7b, 0x7d, 0x7f, + 0x81, 0x84, 0x87, 0x8a, 0x8d, 0x90, 0x94, 0x96, 0x97, 0x97, 0x96, + 0x93, 0x90, 0x8b, 0x87, 0x82, 0x7f, 0x7c, 0x7a, 0x79, 0x79, 0x79, + 0x7a, 0x7b, 0x7c, 0x7c, 0x7c, 0x7c, 0x7b, 0x7a, 0x78, 0x77, 0x75, + 0x73, 0x72, 0x72, 0x72, 0x73, 0x74, 0x75, 0x77, 0x79, 0x7b, 0x7d, + 0x80, 0x83, 0x86, 0x8a, 0x8d, 0x91, 0x94, 0x97, 0x98, 0x98, 0x97, + 0x94, 0x91, 0x8c, 0x88, 0x84, 0x80, 0x7d, 0x7b, 0x7a, 0x79, 0x7a, + 0x7a, 0x7b, 0x7b, 0x7c, 0x7c, 0x7c, 0x7b, 0x7a, 0x78, 0x77, 0x75, + 0x73, 0x72, 0x71, 0x71, 0x72, 0x72, 0x74, 0x75, 0x77, 0x79, 0x7c, + 0x7f, 0x82, 0x86, 0x8a, 0x8f, 0x93, 0x96, 0x99, 0x9a, 0x9a, 0x99, + 0x96, 0x93, 0x8e, 0x89, 0x84, 0x81, 0x7d, 0x7b, 0x7a, 0x79, 0x79, + 0x7a, 0x7b, 0x7b, 0x7c, 0x7c, 0x7c, 0x7b, 0x7a, 0x78, 0x76, 0x74, + 0x72, 0x70, 0x70, 0x70, 0x70, 0x71, 0x72, 0x74, 0x75, 0x78, 0x7a, + 0x7d, 0x81, 0x85, 0x8b, 0x90, 0x95, 0x9a, 0x9d, 0x9f, 0x9f, 0x9d, + 0x99, 0x95, 0x8f, 0x89, 0x84, 0x7f, 0x7c, 0x79, 0x78, 0x78, 0x79, + 0x7a, 0x7b, 0x7c, 0x7c, 0x7d, 0x7c, 0x7b, 0x79, 0x77, 0x74, 0x72, + 0x6f, 0x6e, 0x6d, 0x6d, 0x6e, 0x6f, 0x71, 0x72, 0x74, 0x76, 0x78, + 0x7a, 0x7e, 0x82, 0x88, 0x8e, 0x95, 0x9b, 0xa0, 0xa3, 0xa3, 0xa2, + 0x9e, 0x9a, 0x94, 0x8d, 0x87, 0x81, 0x7c, 0x79, 0x77, 0x77, 0x78, + 0x79, 0x7a, 0x7c, 0x7d, 0x7e, 0x7d, 0x7c, 0x7b, 0x78, 0x75, 0x72, + 0x6f, 0x6c, 0x6b, 0x6b, 0x6c, 0x6d, 0x6f, 0x71, 0x73, 0x74, 0x75, + 0x77, 0x7a, 0x7f, 0x85, 0x8c, 0x94, 0x9c, 0xa2, 0xa7, 0xa9, 0xa7, + 0xa3, 0x9d, 0x97, 0x8f, 0x87, 0x81, 0x7c, 0x78, 0x76, 0x76, 0x77, + 0x78, 0x7a, 0x7c, 0x7e, 0x7f, 0x7f, 0x7e, 0x7c, 0x79, 0x75, 0x70, + 0x6c, 0x69, 0x67, 0x67, 0x68, 0x6b, 0x6e, 0x70, 0x71, 0x73, 0x74, + 0x76, 0x7a, 0x80, 0x88, 0x90, 0x9a, 0xa2, 0xa9, 0xad, 0xad, 0xaa, + 0xa4, 0x9c, 0x94, 0x8b, 0x83, 0x7c, 0x78, 0x75, 0x74, 0x75, 0x77, + 0x79, 0x7c, 0x7f, 0x80, 0x81, 0x80, 0x7e, 0x7a, 0x75, 0x6f, 0x6a, + 0x66, 0x63, 0x63, 0x65, 0x69, 0x6d, 0x71, 0x73, 0x74, 0x75, 0x76, + 0x78, 0x7d, 0x84, 0x8e, 0x99, 0xa3, 0xab, 0xb1, 0xb3, 0xb0, 0xaa, + 0xa1, 0x97, 0x8d, 0x84, 0x7c, 0x77, 0x74, 0x73, 0x74, 0x76, 0x79, + 0x7d, 0x80, 0x82, 0x83, 0x82, 0x7f, 0x7b, 0x75, 0x6e, 0x67, 0x62, + 0x5f, 0x5f, 0x62, 0x68, 0x6d, 0x71, 0x73, 0x74, 0x73, 0x74, 0x77, + 0x7c, 0x84, 0x8f, 0x9b, 0xa6, 0xaf, 0xb5, 0xb6, 0xb2, 0xab, 0xa1, + 0x96, 0x8b, 0x81, 0x7a, 0x75, 0x72, 0x72, 0x74, 0x77, 0x7b, 0x7f, + 0x83, 0x85, 0x86, 0x85, 0x81, 0x7b, 0x72, 0x68, 0x5f, 0x59, 0x56, + 0x58, 0x5e, 0x66, 0x6e, 0x72, 0x74, 0x73, 0x73, 0x74, 0x78, 0x80, + 0x8b, 0x98, 0xa5, 0xb1, 0xb8, 0xbc, 0xba, 0xb3, 0xa8, 0x9b, 0x8f, + 0x83, 0x7a, 0x74, 0x71, 0x70, 0x71, 0x74, 0x78, 0x7c, 0x81, 0x85, + 0x89, 0x8b, 0x88, 0x83, 0x79, 0x6d, 0x60, 0x56, 0x50, 0x4f, 0x55, + 0x5e, 0x69, 0x71, 0x74, 0x76, 0x75, 0x75, 0x76, 0x7c, 0x85, 0x93, + 0xa2, 0xb0, 0xba, 0xc0, 0xc0, 0xb9, 0xaf, 0xa1, 0x94, 0x86, 0x7c, + 0x75, 0x72, 0x70, 0x70, 0x72, 0x76, 0x7b, 0x80, 0x86, 0x8a, 0x8d, + 0x8b, 0x86, 0x7c, 0x6e, 0x60, 0x53, 0x4b, 0x4a, 0x50, 0x5b, 0x66, + 0x6f, 0x73, 0x76, 0x75, 0x75, 0x77, 0x7d, 0x86, 0x94, 0xa4, 0xb2, + 0xbd, 0xc2, 0xc2, 0xba, 0xaf, 0xa1, 0x93, 0x85, 0x7b, 0x74, 0x70, + 0x6f, 0x6f, 0x72, 0x75, 0x7a, 0x80, 0x87, 0x8c, 0x8f, 0x8e, 0x86, + 0x7a, 0x6a, 0x5b, 0x4d, 0x46, 0x46, 0x4f, 0x5b, 0x67, 0x70, 0x75, + 0x77, 0x76, 0x77, 0x7a, 0x82, 0x8d, 0x9c, 0xab, 0xb9, 0xc1, 0xc4, + 0xc1, 0xb7, 0xab, 0x9a, 0x8c, 0x7e, 0x76, 0x70, 0x6e, 0x6e, 0x6f, + 0x72, 0x76, 0x7c, 0x82, 0x8a, 0x8f, 0x91, 0x8e, 0x85, 0x75, 0x63, + 0x52, 0x47, 0x44, 0x4a, 0x54, 0x5e, 0x67, 0x6d, 0x72, 0x73, 0x75, + 0x79, 0x81, 0x8b, 0x9a, 0xa9, 0xb7, 0xc1, 0xc5, 0xc3, 0xba, 0xad, + 0x9d, 0x8e, 0x80, 0x76, 0x70, 0x6d, 0x6d, 0x6e, 0x70, 0x74, 0x79, + 0x82, 0x8b, 0x93, 0x97, 0x95, 0x8b, 0x7b, 0x67, 0x54, 0x47, 0x41, + 0x45, 0x4e, 0x59, 0x63, 0x6a, 0x6d, 0x6f, 0x72, 0x77, 0x80, 0x8d, + 0x9c, 0xac, 0xbb, 0xc4, 0xc7, 0xc3, 0xb8, 0xaa, 0x99, 0x89, 0x7d, + 0x74, 0x70, 0x6d, 0x6d, 0x6f, 0x72, 0x77, 0x7e, 0x87, 0x8f, 0x95, + 0x96, 0x91, 0x84, 0x72, 0x5e, 0x4c, 0x43, 0x43, 0x4a, 0x52, 0x5c, + 0x63, 0x69, 0x6c, 0x71, 0x77, 0x82, 0x90, 0x9f, 0xaf, 0xbb, 0xc4, + 0xc6, 0xc1, 0xb5, 0xa7, 0x96, 0x87, 0x7b, 0x74, 0x6f, 0x6e, 0x6e, + 0x70, 0x74, 0x79, 0x80, 0x88, 0x90, 0x94, 0x93, 0x8c, 0x7e, 0x6b, + 0x59, 0x4b, 0x43, 0x43, 0x49, 0x51, 0x5a, 0x61, 0x68, 0x70, 0x7a, + 0x86, 0x95, 0xa4, 0xb3, 0xbf, 0xc6, 0xc7, 0xc1, 0xb5, 0xa5, 0x93, + 0x83, 0x77, 0x6f, 0x6b, 0x6b, 0x6d, 0x70, 0x75, 0x7b, 0x82, 0x88, + 0x8e, 0x91, 0x90, 0x89, 0x7c, 0x6c, 0x5b, 0x4e, 0x46, 0x45, 0x4a, + 0x51, 0x59, 0x62, 0x6b, 0x76, 0x84, 0x93, 0xa2, 0xb0, 0xba, 0xc1, + 0xc2, 0xbd, 0xb3, 0xa5, 0x96, 0x87, 0x7a, 0x71, 0x6c, 0x6b, 0x6d, + 0x71, 0x75, 0x7b, 0x82, 0x87, 0x8c, 0x8d, 0x8b, 0x82, 0x77, 0x68, + 0x5a, 0x4f, 0x4a, 0x4a, 0x4d, 0x54, 0x5c, 0x67, 0x74, 0x83, 0x92, + 0xa2, 0xb0, 0xbb, 0xc0, 0xc0, 0xba, 0xb0, 0xa2, 0x93, 0x85, 0x79, + 0x70, 0x6b, 0x69, 0x6a, 0x6e, 0x73, 0x7a, 0x80, 0x86, 0x8a, 0x8b, + 0x89, 0x83, 0x78, 0x6b, 0x5e, 0x52, 0x4d, 0x4b, 0x4f, 0x56, 0x61, + 0x6d, 0x7d, 0x8e, 0x9f, 0xaf, 0xb9, 0xbf, 0xbe, 0xb9, 0xae, 0xa2, + 0x93, 0x86, 0x7a, 0x71, 0x6a, 0x67, 0x67, 0x69, 0x6e, 0x75, 0x7e, + 0x85, 0x8b, 0x8d, 0x8b, 0x84, 0x7a, 0x6d, 0x60, 0x54, 0x4d, 0x4a, + 0x4d, 0x57, 0x64, 0x76, 0x88, 0x9a, 0xa9, 0xb6, 0xbc, 0xbd, 0xb9, + 0xb0, 0xa4, 0x96, 0x89, 0x7d, 0x73, 0x6b, 0x66, 0x64, 0x65, 0x69, + 0x70, 0x79, 0x82, 0x8a, 0x8f, 0x8e, 0x89, 0x81, 0x75, 0x68, 0x5b, + 0x51, 0x4c, 0x4b, 0x51, 0x5c, 0x6e, 0x80, 0x93, 0xa5, 0xb2, 0xbb, + 0xbd, 0xbb, 0xb2, 0xa8, 0x9a, 0x8d, 0x7f, 0x72, 0x69, 0x61, 0x5e, + 0x5e, 0x64, 0x6b, 0x76, 0x82, 0x8c, 0x93, 0x95, 0x94, 0x8c, 0x83, + 0x76, 0x6a, 0x5f, 0x56, 0x50, 0x4d, 0x4e, 0x54, 0x5f, 0x6f, 0x81, + 0x96, 0xa9, 0xb9, 0xc2, 0xc5, 0xc0, 0xb6, 0xa7, 0x96, 0x87, 0x79, + 0x6e, 0x65, 0x60, 0x5d, 0x5c, 0x5f, 0x65, 0x6e, 0x7b, 0x8a, 0x98, + 0xa2, 0xa8, 0xa6, 0x9d, 0x8f, 0x7d, 0x6c, 0x5d, 0x53, 0x4d, 0x4c, + 0x4c, 0x4e, 0x50, 0x54, 0x5c, 0x69, 0x7d, 0x93, 0xab, 0xbe, 0xcc, + 0xcf, 0xca, 0xbb, 0xa8, 0x93, 0x7f, 0x71, 0x67, 0x62, 0x60, 0x60, + 0x61, 0x63, 0x67, 0x6d, 0x76, 0x82, 0x8f, 0x9a, 0xa2, 0xa4, 0xa0, + 0x96, 0x88, 0x79, 0x6c, 0x63, 0x5f, 0x5f, 0x63, 0x69, 0x70, 0x78, + 0x80, 0x87, 0x8e, 0x92, 0x95, 0x93, 0x90, 0x87, 0x7e, 0x72, 0x67, + 0x5b, 0x53, 0x4f, 0x52, 0x5d, 0x6c, 0x80, 0x92, 0xa4, 0xaf, 0xb6, + 0xb6, 0xb1, 0xaa, 0xa0, 0x97, 0x8c, 0x83, 0x78, 0x6f, 0x65, 0x5e, + 0x5a, 0x59, 0x5e, 0x66, 0x73, 0x7f, 0x8c, 0x95, 0x9b, 0x9b, 0x98, + 0x91, 0x89, 0x81, 0x79, 0x73, 0x6e, 0x6c, 0x69, 0x68, 0x68, 0x69, + 0x6c, 0x71, 0x78, 0x80, 0x89, 0x90, 0x95, 0x96, 0x95, 0x91, 0x8b, + 0x85, 0x7f, 0x7b, 0x77, 0x75, 0x73, 0x73, 0x73, 0x73, 0x75, 0x77, + 0x7b, 0x80, 0x85, 0x8a, 0x8e, 0x90, 0x90, 0x8d, 0x89, 0x84, 0x7f, + 0x7b, 0x78, 0x76, 0x75, 0x75, 0x76, 0x77, 0x78, 0x7a, 0x7d, 0x7f, + 0x82, 0x85, 0x88, 0x89, 0x89, 0x88, 0x85, 0x81, 0x7d, 0x7a, 0x78, + 0x77, 0x77, 0x78, 0x79, 0x7a, 0x7c, 0x7d, 0x7e, 0x80, 0x82, 0x83, + 0x85, 0x85, 0x85, 0x85, 0x83, 0x81, 0x7e, 0x7c, 0x7a, 0x79, 0x79, + 0x7a, 0x7b, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x81, 0x82, 0x83, 0x83, + 0x83, 0x82, 0x84, 0x84, 0x87, 0x86, 0x84, 0x7e, 0x77, 0x6f, 0x68, + 0x65, 0x65, 0x6b, 0x73, 0x7e, 0x87, 0x8f, 0x92, 0x94, 0x92, 0x90, + 0x8e, 0x8b, 0x8a, 0x88, 0x85, 0x80, 0x7b, 0x73, 0x6e, 0x6a, 0x6a, + 0x6e, 0x74, 0x7c, 0x84, 0x8a, 0x8d, 0x8e, 0x8b, 0x88, 0x85, 0x82, + 0x80, 0x7d, 0x7c, 0x7a, 0x78, 0x75, 0x73, 0x72, 0x73, 0x76, 0x7a, + 0x80, 0x85, 0x89, 0x8a, 0x8a, 0x88, 0x85, 0x82, 0x7f, 0x7e, 0x7d, + 0x7d, 0x7c, 0x7c, 0x7b, 0x7a, 0x79, 0x79, 0x7a, 0x7d, 0x80, 0x83, + 0x85, 0x86, 0x86, 0x85, 0x83, 0x80, 0x7f, 0x7d, 0x7c, 0x7c, 0x7c, + 0x7d, 0x7c, 0x7c, 0x7c, 0x7c, 0x7d, 0x7e, 0x80, 0x82, 0x83, 0x84, + 0x84, 0x83, 0x81, 0x7f, 0x7d, 0x7c, 0x7c, 0x7c, 0x7d, 0x7d, 0x7d, + 0x7d, 0x7d, 0x7d, 0x7d, 0x7e, 0x80, 0x81, 0x82, 0x82, 0x82, 0x81, + 0x80, 0x7e, 0x7d, 0x7c, 0x7c, 0x7d, 0x7d, 0x7e, 0x7e, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x81, 0x81, 0x81, 0x80, 0x80, 0x7f, + 0x7e, 0x7d, 0x7d, 0x7d, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7e, 0x7e, 0x7e, + 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, + 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x80, + 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, + 0x80, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, + 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x7f, + 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, + 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x80, + 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, + 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, + 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x80, + 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, + 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, + 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, + 0x80, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, + 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, + 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, + 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x80, + 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x80, + 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x80, + 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, + 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, + 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, + 0x80, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x7f, + 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, + }, + { // 6 + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, + 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, + 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, 0x7f, 0x7e, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x7f, 0x7f, 0x7e, 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, + 0x7e, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x81, 0x81, 0x82, 0x81, 0x82, + 0x81, 0x81, 0x80, 0x7f, 0x7f, 0x7e, 0x7e, 0x7c, 0x7d, 0x7c, 0x7c, + 0x7c, 0x7c, 0x7e, 0x7d, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x84, + 0x85, 0x84, 0x85, 0x82, 0x82, 0x7f, 0x7e, 0x7c, 0x7a, 0x79, 0x77, + 0x77, 0x75, 0x77, 0x76, 0x7a, 0x7a, 0x7f, 0x81, 0x84, 0x87, 0x89, + 0x8b, 0x8c, 0x8c, 0x8c, 0x8b, 0x88, 0x86, 0x81, 0x7e, 0x79, 0x76, + 0x71, 0x71, 0x6b, 0x6d, 0x6d, 0x6e, 0x74, 0x74, 0x7f, 0x80, 0x87, + 0x8c, 0x90, 0x95, 0x96, 0x97, 0x96, 0x95, 0x8f, 0x8a, 0x81, 0x7d, + 0x76, 0x70, 0x6b, 0x65, 0x64, 0x63, 0x64, 0x69, 0x6d, 0x73, 0x7d, + 0x83, 0x8c, 0x91, 0x98, 0x9c, 0x9e, 0x9e, 0x9d, 0x97, 0x90, 0x87, + 0x80, 0x79, 0x71, 0x6a, 0x62, 0x61, 0x5a, 0x61, 0x60, 0x6b, 0x6e, + 0x78, 0x82, 0x88, 0x92, 0x96, 0x9f, 0x9f, 0xa2, 0x9e, 0x9e, 0x96, + 0x8f, 0x84, 0x7e, 0x73, 0x6d, 0x65, 0x61, 0x5d, 0x5b, 0x61, 0x62, + 0x6d, 0x6e, 0x7e, 0x83, 0x8c, 0x92, 0x99, 0x9f, 0x9f, 0xa0, 0x9e, + 0x9c, 0x92, 0x8c, 0x81, 0x7b, 0x70, 0x6c, 0x64, 0x62, 0x5b, 0x60, + 0x62, 0x68, 0x6d, 0x73, 0x82, 0x83, 0x8f, 0x90, 0x9b, 0x9d, 0x9e, + 0x9e, 0x9c, 0x98, 0x91, 0x88, 0x81, 0x78, 0x70, 0x6a, 0x65, 0x62, + 0x5e, 0x65, 0x62, 0x6d, 0x6d, 0x79, 0x82, 0x84, 0x90, 0x90, 0x9b, + 0x9b, 0x9c, 0x9d, 0x9a, 0x96, 0x8f, 0x84, 0x7f, 0x74, 0x71, 0x6b, + 0x66, 0x63, 0x62, 0x64, 0x67, 0x6d, 0x6e, 0x7e, 0x7e, 0x88, 0x8d, + 0x94, 0x9b, 0x99, 0x9d, 0x9c, 0x99, 0x93, 0x8a, 0x82, 0x7f, 0x75, + 0x73, 0x6a, 0x66, 0x61, 0x66, 0x66, 0x68, 0x6d, 0x70, 0x7c, 0x7b, + 0x87, 0x8b, 0x94, 0x97, 0x97, 0x9c, 0x9e, 0x9a, 0x96, 0x8e, 0x89, + 0x82, 0x78, 0x74, 0x69, 0x65, 0x5f, 0x62, 0x61, 0x66, 0x67, 0x70, + 0x78, 0x7b, 0x87, 0x8c, 0x95, 0x98, 0x9a, 0x9f, 0x9f, 0x9d, 0x98, + 0x90, 0x8a, 0x80, 0x7a, 0x71, 0x69, 0x62, 0x60, 0x60, 0x60, 0x66, + 0x67, 0x71, 0x79, 0x7e, 0x88, 0x8e, 0x96, 0x98, 0x9d, 0xa0, 0x9e, + 0x9d, 0x95, 0x8f, 0x88, 0x80, 0x75, 0x70, 0x66, 0x62, 0x5f, 0x60, + 0x63, 0x65, 0x6b, 0x72, 0x7b, 0x80, 0x8a, 0x8d, 0x98, 0x99, 0x9c, + 0x9e, 0x9c, 0x9a, 0x93, 0x8e, 0x87, 0x7e, 0x76, 0x6f, 0x65, 0x62, + 0x60, 0x61, 0x64, 0x67, 0x6c, 0x75, 0x79, 0x80, 0x8b, 0x8f, 0x98, + 0x98, 0x9d, 0x9f, 0x9b, 0x9b, 0x93, 0x8d, 0x85, 0x7d, 0x75, 0x6e, + 0x65, 0x64, 0x60, 0x5f, 0x63, 0x68, 0x6e, 0x77, 0x7c, 0x83, 0x8b, + 0x8e, 0x97, 0x98, 0x9b, 0x9d, 0x9b, 0x9a, 0x92, 0x8c, 0x88, 0x7d, + 0x75, 0x6e, 0x66, 0x64, 0x61, 0x60, 0x63, 0x66, 0x6b, 0x75, 0x78, + 0x81, 0x8a, 0x8f, 0x97, 0x97, 0x9d, 0x9f, 0x9d, 0x9a, 0x93, 0x8d, + 0x87, 0x7c, 0x76, 0x6e, 0x66, 0x65, 0x5f, 0x61, 0x61, 0x67, 0x6c, + 0x74, 0x79, 0x83, 0x89, 0x8e, 0x96, 0x96, 0x9e, 0x9c, 0x9d, 0x99, + 0x94, 0x8d, 0x86, 0x7e, 0x76, 0x6d, 0x67, 0x64, 0x60, 0x62, 0x62, + 0x69, 0x6c, 0x75, 0x79, 0x80, 0x87, 0x8c, 0x94, 0x94, 0x9a, 0x9d, + 0x9a, 0x9a, 0x97, 0x90, 0x8a, 0x81, 0x7b, 0x74, 0x69, 0x69, 0x63, + 0x5e, 0x5d, 0x61, 0x63, 0x6c, 0x79, 0x81, 0x8e, 0x94, 0x9f, 0xa1, + 0xa4, 0xa8, 0xa1, 0x9c, 0x8e, 0x84, 0x7a, 0x70, 0x66, 0x62, 0x5d, + 0x4d, 0x57, 0x5f, 0x5b, 0x67, 0x82, 0x88, 0x8e, 0x9e, 0xa8, 0xa1, + 0xa1, 0xa7, 0xa2, 0x92, 0x93, 0x8d, 0x7c, 0x79, 0x76, 0x6f, 0x64, + 0x5e, 0x58, 0x4d, 0x5c, 0x61, 0x61, 0x80, 0x86, 0x93, 0x9b, 0xa6, + 0xa4, 0xa0, 0xa3, 0xa2, 0x96, 0x92, 0x8f, 0x82, 0x7a, 0x77, 0x70, + 0x68, 0x5f, 0x58, 0x4f, 0x51, 0x68, 0x59, 0x7f, 0x84, 0x91, 0x9d, + 0xa1, 0xa9, 0x9d, 0xa1, 0x9b, 0x95, 0x8a, 0x8b, 0x83, 0x7b, 0x77, + 0x74, 0x69, 0x65, 0x59, 0x51, 0x51, 0x67, 0x59, 0x78, 0x89, 0x88, + 0x9f, 0x9f, 0xa8, 0x9b, 0xa3, 0x9b, 0x97, 0x91, 0x8c, 0x87, 0x7c, + 0x79, 0x73, 0x69, 0x67, 0x5b, 0x53, 0x4d, 0x63, 0x58, 0x6e, 0x8c, + 0x82, 0xa1, 0x9f, 0xa7, 0x9e, 0x9f, 0x9a, 0x94, 0x94, 0x88, 0x8a, + 0x7f, 0x7b, 0x75, 0x6b, 0x6b, 0x5b, 0x58, 0x4a, 0x62, 0x5b, 0x65, + 0x8d, 0x81, 0x9c, 0x9e, 0xa5, 0x9f, 0x9f, 0x9c, 0x94, 0x94, 0x8d, + 0x87, 0x83, 0x7b, 0x7a, 0x6e, 0x6e, 0x66, 0x59, 0x52, 0x54, 0x66, + 0x51, 0x82, 0x83, 0x89, 0xa4, 0xa0, 0xa5, 0x9f, 0xa5, 0x94, 0x94, + 0x93, 0x86, 0x86, 0x7e, 0x79, 0x75, 0x6c, 0x6c, 0x5c, 0x59, 0x4c, + 0x63, 0x5a, 0x65, 0x8d, 0x7c, 0x9a, 0xa0, 0x9f, 0x9f, 0xa2, 0x9d, + 0x90, 0x97, 0x8d, 0x84, 0x86, 0x79, 0x77, 0x6f, 0x6d, 0x65, 0x58, + 0x55, 0x4e, 0x68, 0x54, 0x7b, 0x8b, 0x82, 0xa3, 0x9d, 0xa2, 0x9d, + 0xa1, 0x98, 0x92, 0x92, 0x8b, 0x84, 0x84, 0x79, 0x7c, 0x6e, 0x6d, + 0x66, 0x56, 0x55, 0x4f, 0x67, 0x52, 0x7c, 0x83, 0x81, 0xa2, 0x9a, + 0xa3, 0xa0, 0xa2, 0x99, 0x99, 0x93, 0x8d, 0x88, 0x83, 0x7a, 0x7a, + 0x6e, 0x6a, 0x64, 0x56, 0x53, 0x54, 0x63, 0x56, 0x7d, 0x84, 0x84, + 0xa0, 0x9e, 0xa4, 0x9f, 0xa2, 0x9a, 0x96, 0x93, 0x8b, 0x89, 0x83, + 0x7b, 0x79, 0x6f, 0x68, 0x64, 0x59, 0x50, 0x52, 0x62, 0x59, 0x76, + 0x89, 0x86, 0x9e, 0x9e, 0xa2, 0xa2, 0xa0, 0x9a, 0x97, 0x92, 0x8e, + 0x8a, 0x83, 0x7f, 0x76, 0x76, 0x6d, 0x66, 0x5c, 0x5a, 0x4d, 0x5d, + 0x5e, 0x62, 0x89, 0x81, 0x95, 0x9f, 0x9f, 0xa0, 0xa1, 0x9b, 0x97, + 0x96, 0x8f, 0x8c, 0x84, 0x84, 0x78, 0x76, 0x74, 0x6b, 0x63, 0x5a, + 0x54, 0x4d, 0x66, 0x57, 0x74, 0x8a, 0x85, 0xa1, 0x9d, 0xa5, 0x9e, + 0xa1, 0x98, 0x98, 0x93, 0x8d, 0x88, 0x81, 0x81, 0x75, 0x76, 0x6e, + 0x6d, 0x5d, 0x5a, 0x4f, 0x50, 0x66, 0x55, 0x81, 0x86, 0x8b, 0xa3, + 0x9d, 0xa4, 0x9e, 0x9f, 0x9a, 0x98, 0x91, 0x8e, 0x86, 0x83, 0x7d, + 0x78, 0x77, 0x6e, 0x6c, 0x63, 0x5a, 0x53, 0x4d, 0x66, 0x5a, 0x79, + 0x8b, 0x85, 0xa0, 0x9d, 0x9f, 0x9e, 0xa0, 0x97, 0x98, 0x91, 0x90, + 0x88, 0x82, 0x83, 0x77, 0x78, 0x70, 0x6e, 0x65, 0x5c, 0x55, 0x49, + 0x64, 0x59, 0x6f, 0x8b, 0x84, 0x9e, 0x9b, 0xa3, 0xa0, 0x9e, 0x99, + 0x99, 0x95, 0x8b, 0x8f, 0x82, 0x81, 0x7b, 0x77, 0x73, 0x6e, 0x6e, + 0x60, 0x5e, 0x51, 0x4f, 0x67, 0x56, 0x7a, 0x8a, 0x89, 0xa2, 0xa1, + 0xa3, 0x9c, 0xa0, 0x96, 0x96, 0x91, 0x8e, 0x8a, 0x83, 0x82, 0x79, + 0x78, 0x6e, 0x6e, 0x68, 0x5f, 0x5d, 0x4c, 0x60, 0x5e, 0x61, 0x88, + 0x80, 0x96, 0x9f, 0xa0, 0xa1, 0x9f, 0x9e, 0x92, 0x96, 0x8c, 0x8b, + 0x85, 0x84, 0x81, 0x7a, 0x7a, 0x71, 0x6f, 0x67, 0x5f, 0x58, 0x4d, + 0x60, 0x5e, 0x5e, 0x89, 0x85, 0x93, 0xa4, 0xa0, 0xa2, 0x9f, 0x9e, + 0x94, 0x96, 0x8f, 0x89, 0x86, 0x80, 0x7f, 0x7b, 0x77, 0x75, 0x72, + 0x6c, 0x5f, 0x5e, 0x4c, 0x5b, 0x64, 0x57, 0x82, 0x86, 0x8c, 0xa0, + 0xa3, 0xa0, 0xa0, 0xa3, 0x91, 0x97, 0x90, 0x89, 0x8a, 0x81, 0x81, + 0x7d, 0x79, 0x72, 0x72, 0x6e, 0x64, 0x5c, 0x53, 0x51, 0x63, 0x58, + 0x73, 0x8c, 0x87, 0x9f, 0x9e, 0xa5, 0x9c, 0xa0, 0x97, 0x93, 0x95, + 0x8b, 0x8e, 0x84, 0x86, 0x7e, 0x7d, 0x75, 0x73, 0x72, 0x68, 0x64, + 0x59, 0x4e, 0x54, 0x62, 0x5b, 0x80, 0x8d, 0x8d, 0xa5, 0xa0, 0xa5, + 0x9e, 0x9e, 0x96, 0x92, 0x91, 0x89, 0x8a, 0x7f, 0x83, 0x7b, 0x78, + 0x76, 0x76, 0x72, 0x6a, 0x64, 0x58, 0x4b, 0x59, 0x60, 0x5e, 0x87, + 0x8a, 0x96, 0xa5, 0xa5, 0xa1, 0x9a, 0x9d, 0x91, 0x93, 0x8d, 0x88, + 0x85, 0x7e, 0x82, 0x78, 0x7d, 0x75, 0x78, 0x74, 0x6d, 0x66, 0x58, + 0x4d, 0x57, 0x63, 0x5c, 0x82, 0x8d, 0x92, 0xa6, 0xa7, 0xa3, 0x9c, + 0x9a, 0x92, 0x8d, 0x8a, 0x83, 0x8a, 0x7e, 0x82, 0x80, 0x7d, 0x7a, + 0x78, 0x79, 0x6f, 0x6b, 0x5c, 0x52, 0x4b, 0x68, 0x58, 0x70, 0x93, + 0x8b, 0xa2, 0xa2, 0xa6, 0x9a, 0x96, 0x96, 0x88, 0x8e, 0x86, 0x85, + 0x83, 0x81, 0x85, 0x7d, 0x80, 0x79, 0x7d, 0x72, 0x72, 0x64, 0x5b, + 0x4a, 0x51, 0x64, 0x54, 0x85, 0x92, 0x9c, 0xa7, 0xa8, 0xa8, 0x98, + 0x95, 0x8a, 0x88, 0x85, 0x83, 0x85, 0x81, 0x84, 0x80, 0x81, 0x7e, + 0x7c, 0x81, 0x74, 0x73, 0x60, 0x58, 0x45, 0x51, 0x64, 0x5c, 0x89, + 0x92, 0x9b, 0xa4, 0xa7, 0xa8, 0x94, 0x93, 0x86, 0x88, 0x81, 0x84, + 0x87, 0x84, 0x88, 0x82, 0x83, 0x7d, 0x7e, 0x80, 0x77, 0x72, 0x68, + 0x59, 0x4c, 0x45, 0x5c, 0x5b, 0x7c, 0x97, 0x9f, 0xaa, 0xa5, 0xa8, + 0x95, 0x90, 0x87, 0x7f, 0x83, 0x80, 0x81, 0x82, 0x88, 0x8a, 0x8a, + 0x89, 0x83, 0x81, 0x79, 0x76, 0x6b, 0x5c, 0x54, 0x42, 0x4b, 0x66, + 0x66, 0x8c, 0x9e, 0xa7, 0xa9, 0xa2, 0xa4, 0x8c, 0x8a, 0x7c, 0x7f, + 0x7a, 0x7f, 0x85, 0x85, 0x8b, 0x8b, 0x92, 0x8c, 0x85, 0x84, 0x78, + 0x72, 0x6b, 0x65, 0x56, 0x4d, 0x46, 0x58, 0x71, 0x78, 0x9d, 0xa4, + 0xab, 0xa6, 0x9d, 0x8f, 0x82, 0x82, 0x7b, 0x7d, 0x84, 0x83, 0x89, + 0x8e, 0x90, 0x95, 0x89, 0x85, 0x7d, 0x79, 0x71, 0x69, 0x64, 0x62, + 0x59, 0x50, 0x45, 0x61, 0x76, 0x81, 0x9f, 0xa5, 0xad, 0x99, 0x98, + 0x8e, 0x80, 0x7e, 0x7b, 0x81, 0x85, 0x8f, 0x8f, 0x96, 0x93, 0x90, + 0x8d, 0x83, 0x7c, 0x78, 0x71, 0x67, 0x66, 0x66, 0x5f, 0x59, 0x53, + 0x52, 0x6d, 0x7b, 0x92, 0x9c, 0xa4, 0xa5, 0x90, 0x91, 0x80, 0x80, + 0x7d, 0x80, 0x89, 0x8e, 0x94, 0x93, 0x98, 0x8e, 0x8c, 0x81, 0x78, + 0x74, 0x6e, 0x70, 0x6c, 0x6d, 0x6b, 0x6b, 0x62, 0x61, 0x50, 0x60, + 0x72, 0x80, 0x99, 0x9a, 0xa9, 0x9b, 0x95, 0x88, 0x84, 0x85, 0x7f, + 0x88, 0x8a, 0x93, 0x92, 0x94, 0x92, 0x89, 0x87, 0x79, 0x75, 0x70, + 0x6e, 0x70, 0x72, 0x71, 0x6e, 0x68, 0x61, 0x59, 0x4e, 0x62, 0x73, + 0x8e, 0x9a, 0xa3, 0xa8, 0x9b, 0x91, 0x84, 0x83, 0x80, 0x83, 0x88, + 0x89, 0x94, 0x93, 0x94, 0x90, 0x88, 0x82, 0x79, 0x76, 0x6f, 0x71, + 0x70, 0x75, 0x77, 0x71, 0x6d, 0x63, 0x60, 0x4f, 0x51, 0x62, 0x7d, + 0x9c, 0xa1, 0xa9, 0xa2, 0x9c, 0x89, 0x80, 0x7e, 0x80, 0x87, 0x87, + 0x91, 0x96, 0x97, 0x92, 0x8e, 0x86, 0x7e, 0x74, 0x73, 0x70, 0x71, + 0x74, 0x76, 0x7a, 0x75, 0x6b, 0x63, 0x5c, 0x50, 0x4f, 0x63, 0x87, + 0xa3, 0xa8, 0xa6, 0xa0, 0x96, 0x86, 0x76, 0x77, 0x80, 0x8d, 0x93, + 0x91, 0x97, 0x97, 0x92, 0x86, 0x7c, 0x77, 0x74, 0x73, 0x73, 0x73, + 0x78, 0x7d, 0x7a, 0x76, 0x69, 0x65, 0x5d, 0x55, 0x51, 0x60, 0x86, + 0xa3, 0xac, 0xa2, 0x9a, 0x92, 0x82, 0x74, 0x71, 0x85, 0x96, 0x9c, + 0x97, 0x8f, 0x96, 0x90, 0x86, 0x75, 0x73, 0x77, 0x7a, 0x7d, 0x75, + 0x7a, 0x7a, 0x7d, 0x70, 0x61, 0x5f, 0x59, 0x52, 0x4e, 0x68, 0x97, + 0xb6, 0xb5, 0x9c, 0x8d, 0x84, 0x7c, 0x6d, 0x6e, 0x8b, 0xa3, 0xa9, + 0x95, 0x8a, 0x89, 0x8a, 0x80, 0x71, 0x71, 0x7b, 0x80, 0x7c, 0x76, + 0x77, 0x7d, 0x7c, 0x72, 0x62, 0x60, 0x5a, 0x54, 0x4c, 0x65, 0x9b, + 0xbd, 0xb9, 0x96, 0x86, 0x80, 0x7c, 0x70, 0x6f, 0x87, 0xa6, 0xaf, + 0x9b, 0x86, 0x80, 0x87, 0x82, 0x76, 0x74, 0x7d, 0x87, 0x80, 0x75, + 0x71, 0x77, 0x7f, 0x77, 0x66, 0x5d, 0x5d, 0x5c, 0x54, 0x55, 0x7d, + 0xab, 0xc4, 0xac, 0x8a, 0x7b, 0x7a, 0x7a, 0x73, 0x7a, 0x91, 0xa9, + 0xa5, 0x92, 0x7e, 0x7d, 0x81, 0x7c, 0x74, 0x76, 0x80, 0x83, 0x7b, + 0x74, 0x77, 0x7f, 0x7d, 0x72, 0x60, 0x5a, 0x5c, 0x5c, 0x56, 0x60, + 0x8c, 0xb9, 0xc4, 0xa4, 0x82, 0x71, 0x78, 0x7d, 0x7d, 0x86, 0x95, + 0xa8, 0xa1, 0x8e, 0x7e, 0x76, 0x79, 0x74, 0x7a, 0x83, 0x8b, 0x85, + 0x76, 0x71, 0x78, 0x80, 0x7a, 0x71, 0x66, 0x63, 0x5f, 0x5a, 0x59, + 0x60, 0x85, 0xae, 0xc1, 0xab, 0x86, 0x70, 0x6f, 0x7a, 0x82, 0x8c, + 0x90, 0x99, 0x98, 0x94, 0x85, 0x7d, 0x76, 0x79, 0x7c, 0x85, 0x8a, + 0x88, 0x7f, 0x74, 0x75, 0x76, 0x79, 0x71, 0x6f, 0x66, 0x67, 0x62, + 0x62, 0x5e, 0x61, 0x81, 0xa7, 0xbd, 0xab, 0x87, 0x71, 0x6f, 0x7a, + 0x87, 0x8e, 0x93, 0x96, 0x96, 0x90, 0x89, 0x7f, 0x7e, 0x7c, 0x82, + 0x87, 0x87, 0x87, 0x7f, 0x7d, 0x77, 0x77, 0x73, 0x72, 0x6c, 0x6a, + 0x66, 0x6a, 0x65, 0x62, 0x57, 0x70, 0x9a, 0xbd, 0xbc, 0x93, 0x76, + 0x62, 0x77, 0x81, 0x95, 0x8d, 0x94, 0x91, 0x95, 0x8d, 0x82, 0x7c, + 0x7d, 0x88, 0x85, 0x85, 0x7b, 0x83, 0x80, 0x81, 0x78, 0x73, 0x6e, + 0x70, 0x71, 0x70, 0x69, 0x68, 0x62, 0x61, 0x55, 0x74, 0x97, 0xc1, + 0xbe, 0x98, 0x77, 0x61, 0x74, 0x80, 0x92, 0x8d, 0x94, 0x8f, 0x98, + 0x90, 0x88, 0x7b, 0x77, 0x7b, 0x88, 0x8b, 0x88, 0x7c, 0x75, 0x7a, + 0x7f, 0x83, 0x78, 0x71, 0x6e, 0x79, 0x75, 0x70, 0x65, 0x60, 0x5d, + 0x58, 0x6f, 0x9c, 0xc2, 0xc4, 0x9d, 0x76, 0x60, 0x6b, 0x7d, 0x92, + 0x90, 0x8f, 0x8e, 0x91, 0x93, 0x88, 0x7d, 0x75, 0x7a, 0x80, 0x88, + 0x81, 0x7d, 0x77, 0x7e, 0x87, 0x88, 0x7e, 0x72, 0x6b, 0x6e, 0x75, + 0x7c, 0x7a, 0x6f, 0x64, 0x5e, 0x60, 0x62, 0x82, 0xa2, 0xc3, 0xb9, + 0x98, 0x73, 0x5e, 0x68, 0x7c, 0x91, 0x91, 0x93, 0x8e, 0x95, 0x90, + 0x8b, 0x7b, 0x75, 0x73, 0x7f, 0x84, 0x85, 0x82, 0x7b, 0x7e, 0x7a, + 0x82, 0x7f, 0x7f, 0x77, 0x76, 0x6f, 0x76, 0x74, 0x76, 0x6c, 0x68, + 0x62, 0x61, 0x60, 0x75, 0x9d, 0xbd, 0xc3, 0xa1, 0x7a, 0x59, 0x5f, + 0x74, 0x96, 0x9b, 0x9e, 0x93, 0x92, 0x8e, 0x88, 0x7c, 0x6f, 0x69, + 0x72, 0x83, 0x8d, 0x90, 0x86, 0x81, 0x7b, 0x7f, 0x7b, 0x7a, 0x71, + 0x78, 0x82, 0x90, 0x8f, 0x81, 0x70, 0x6b, 0x72, 0x80, 0x85, 0x7c, + 0x73, 0x6c, 0x72, 0x72, 0x6f, 0x67, 0x63, 0x61, 0x63, 0x76, 0x96, + 0xb6, 0xbe, 0xa8, 0x85, 0x65, 0x60, 0x71, 0x8a, 0x9b, 0x9a, 0x99, + 0x92, 0x90, 0x87, 0x7d, 0x71, 0x6b, 0x71, 0x7f, 0x8c, 0x91, 0x8a, + 0x80, 0x77, 0x76, 0x78, 0x76, 0x77, 0x77, 0x7d, 0x83, 0x8d, 0x90, + 0x8c, 0x7d, 0x74, 0x70, 0x75, 0x7b, 0x80, 0x7e, 0x78, 0x74, 0x73, + 0x70, 0x6a, 0x68, 0x67, 0x69, 0x65, 0x6e, 0x7d, 0xa1, 0xb8, 0xbe, + 0x9f, 0x77, 0x5b, 0x5d, 0x78, 0x94, 0xa5, 0xa0, 0x97, 0x8c, 0x8c, + 0x86, 0x80, 0x70, 0x6d, 0x6f, 0x81, 0x90, 0x94, 0x8d, 0x7e, 0x77, + 0x75, 0x7c, 0x79, 0x78, 0x72, 0x76, 0x7e, 0x8b, 0x90, 0x8c, 0x7f, + 0x77, 0x74, 0x77, 0x79, 0x79, 0x77, 0x76, 0x79, 0x7a, 0x78, 0x6d, + 0x67, 0x62, 0x69, 0x6a, 0x68, 0x64, 0x77, 0x9c, 0xbe, 0xc6, 0xa7, + 0x7e, 0x5b, 0x5d, 0x75, 0x96, 0xa6, 0xa3, 0x95, 0x8a, 0x86, 0x87, + 0x84, 0x7b, 0x71, 0x6e, 0x77, 0x85, 0x92, 0x93, 0x8d, 0x7d, 0x74, + 0x6f, 0x74, 0x78, 0x7d, 0x7a, 0x79, 0x76, 0x77, 0x76, 0x72, 0x6d, + 0x68, 0x6b, 0x69, 0x69, 0x63, 0x79, 0x98, 0xbf, 0xc6, 0xb1, 0x84, + 0x60, 0x5a, 0x6f, 0x92, 0xa5, 0xa8, 0x99, 0x8b, 0x83, 0x85, 0x85, + 0x80, 0x75, 0x71, 0x75, 0x83, 0x8f, 0x93, 0x8a, 0x7d, 0x72, 0x6e, + 0x73, 0x7a, 0x7e, 0x7b, 0x76, 0x72, 0x72, 0x71, 0x73, 0x70, 0x71, + 0x6d, 0x6b, 0x63, 0x67, 0x80, 0xa4, 0xc4, 0xc1, 0xa6, 0x78, 0x5e, + 0x5e, 0x7a, 0x99, 0xa7, 0xa2, 0x91, 0x86, 0x82, 0x86, 0x85, 0x80, + 0x75, 0x72, 0x77, 0x85, 0x8f, 0x91, 0x86, 0x79, 0x70, 0x6f, 0x77, + 0x7e, 0x81, 0x7b, 0x76, 0x71, 0x71, 0x71, 0x74, 0x72, 0x73, 0x6e, + 0x69, 0x63, 0x6f, 0x8d, 0xb1, 0xc3, 0xb5, 0x95, 0x6d, 0x60, 0x66, + 0x86, 0x9c, 0xa7, 0x9b, 0x8d, 0x82, 0x81, 0x84, 0x83, 0x7e, 0x76, + 0x76, 0x7c, 0x89, 0x8d, 0x8a, 0x7c, 0x74, 0x6f, 0x75, 0x7a, 0x80, + 0x7c, 0x77, 0x71, 0x71, 0x70, 0x72, 0x72, 0x73, 0x72, 0x6d, 0x67, + 0x67, 0x7e, 0x9e, 0xc0, 0xc0, 0xac, 0x82, 0x68, 0x62, 0x77, 0x91, + 0xa2, 0xa0, 0x92, 0x86, 0x80, 0x85, 0x85, 0x83, 0x7a, 0x77, 0x77, + 0x82, 0x88, 0x8c, 0x85, 0x7c, 0x73, 0x72, 0x74, 0x79, 0x7b, 0x7b, + 0x78, 0x76, 0x74, 0x74, 0x74, 0x73, 0x72, 0x71, 0x72, 0x6d, 0x6c, + 0x71, 0x87, 0xa2, 0xba, 0xba, 0xa7, 0x86, 0x6f, 0x6b, 0x7a, 0x8f, + 0x9d, 0x9d, 0x92, 0x88, 0x82, 0x84, 0x84, 0x83, 0x7e, 0x7d, 0x7f, + 0x83, 0x84, 0x7f, 0x78, 0x71, 0x72, 0x77, 0x7f, 0x7f, 0x7b, 0x72, + 0x6d, 0x6d, 0x71, 0x75, 0x76, 0x77, 0x72, 0x6d, 0x68, 0x71, 0x88, + 0xa8, 0xbd, 0xb9, 0xa1, 0x80, 0x6d, 0x6c, 0x80, 0x94, 0xa0, 0x9a, + 0x8f, 0x84, 0x81, 0x84, 0x85, 0x84, 0x7f, 0x7e, 0x7f, 0x83, 0x82, + 0x7e, 0x76, 0x72, 0x73, 0x7a, 0x80, 0x81, 0x7b, 0x73, 0x6c, 0x6d, + 0x72, 0x77, 0x78, 0x76, 0x73, 0x6f, 0x6e, 0x70, 0x7f, 0x97, 0xb0, + 0xb8, 0xae, 0x94, 0x7c, 0x6f, 0x75, 0x86, 0x96, 0x9d, 0x98, 0x8d, + 0x83, 0x80, 0x81, 0x83, 0x81, 0x7f, 0x7d, 0x7f, 0x81, 0x81, 0x7d, + 0x77, 0x73, 0x74, 0x7a, 0x80, 0x80, 0x7a, 0x71, 0x6b, 0x6c, 0x72, + 0x79, 0x7c, 0x7a, 0x76, 0x6e, 0x6a, 0x6d, 0x7e, 0x97, 0xae, 0xb7, + 0xad, 0x96, 0x7d, 0x71, 0x76, 0x87, 0x97, 0x9d, 0x97, 0x8c, 0x82, + 0x7e, 0x80, 0x82, 0x82, 0x7d, 0x7a, 0x7c, 0x82, 0x87, 0x87, 0x80, + 0x76, 0x6f, 0x6f, 0x77, 0x7f, 0x83, 0x80, 0x76, 0x6d, 0x6a, 0x6e, + 0x75, 0x7b, 0x7b, 0x79, 0x73, 0x6f, 0x6d, 0x72, 0x80, 0x94, 0xa9, + 0xb1, 0xac, 0x99, 0x85, 0x77, 0x78, 0x83, 0x91, 0x98, 0x97, 0x8e, + 0x85, 0x80, 0x7f, 0x81, 0x81, 0x7f, 0x7b, 0x7b, 0x7d, 0x82, 0x84, + 0x84, 0x7e, 0x77, 0x71, 0x72, 0x77, 0x7d, 0x7f, 0x7d, 0x76, 0x70, + 0x6f, 0x70, 0x75, 0x77, 0x79, 0x77, 0x76, 0x72, 0x71, 0x72, 0x7d, + 0x8d, 0xa0, 0xac, 0xac, 0x9f, 0x8d, 0x7e, 0x78, 0x7e, 0x88, 0x93, + 0x95, 0x92, 0x88, 0x82, 0x7f, 0x80, 0x81, 0x81, 0x7e, 0x7b, 0x7a, + 0x7a, 0x7f, 0x83, 0x86, 0x83, 0x7d, 0x75, 0x72, 0x71, 0x77, 0x7c, + 0x7f, 0x7d, 0x79, 0x74, 0x71, 0x72, 0x76, 0x79, 0x79, 0x77, 0x75, + 0x74, 0x75, 0x78, 0x7b, 0x84, 0x8e, 0x9c, 0xa3, 0xa4, 0x99, 0x8c, + 0x7f, 0x7b, 0x7e, 0x88, 0x90, 0x92, 0x8f, 0x87, 0x82, 0x7d, 0x7e, + 0x7e, 0x81, 0x7f, 0x7e, 0x7a, 0x7a, 0x7b, 0x7f, 0x82, 0x83, 0x81, + 0x7c, 0x78, 0x74, 0x76, 0x78, 0x7d, 0x7f, 0x7f, 0x7d, 0x7a, 0x78, + 0x79, 0x7a, 0x7c, 0x7c, 0x7a, 0x77, 0x76, 0x77, 0x7a, 0x7d, 0x7e, + 0x7f, 0x7f, 0x7e, 0x7f, 0x83, 0x8b, 0x93, 0x9b, 0x9b, 0x97, 0x8d, + 0x84, 0x7f, 0x7f, 0x83, 0x88, 0x8a, 0x88, 0x85, 0x80, 0x7e, 0x7d, + 0x7e, 0x7d, 0x7d, 0x7c, 0x7b, 0x7b, 0x7b, 0x7c, 0x7c, 0x7c, 0x7c, + 0x7c, 0x7b, 0x7b, 0x7b, 0x7b, 0x7a, 0x7a, 0x7a, 0x7b, 0x7c, 0x7c, + 0x7d, 0x7d, 0x7d, 0x7d, 0x7e, 0x7e, 0x7f, 0x7f, 0x80, 0x81, 0x83, + 0x83, 0x83, 0x84, 0x85, 0x88, 0x8c, 0x8f, 0x90, 0x8e, 0x89, 0x85, + 0x82, 0x80, 0x81, 0x83, 0x84, 0x83, 0x82, 0x7f, 0x7e, 0x7c, 0x7b, + 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x79, 0x78, 0x76, 0x75, 0x75, 0x76, + 0x78, 0x79, 0x7a, 0x79, 0x78, 0x79, 0x7e, 0x86, 0x90, 0x97, 0x99, + 0x93, 0x8a, 0x82, 0x7f, 0x81, 0x87, 0x8c, 0x8e, 0x8b, 0x85, 0x81, + 0x7f, 0x80, 0x82, 0x84, 0x81, 0x7e, 0x7a, 0x78, 0x79, 0x7c, 0x7f, + 0x80, 0x7e, 0x7a, 0x77, 0x76, 0x77, 0x7a, 0x7d, 0x7e, 0x7d, 0x7b, + 0x7a, 0x7a, 0x7c, 0x7e, 0x7f, 0x80, 0x7f, 0x7e, 0x7d, 0x7d, 0x7e, + 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x81, 0x80, + 0x81, 0x80, 0x80, 0x80, 0x81, 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x81, 0x81, 0x81, + 0x81, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x7e, 0x7e, + 0x7e, 0x7e, 0x7e, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7e, 0x7e, 0x7e, + 0x7d, 0x7d, 0x7d, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x80, 0x80, 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, 0x81, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x80, 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7d, 0x7c, + 0x7c, 0x7c, 0x7c, 0x7d, 0x7d, 0x7d, 0x7c, 0x7c, 0x7b, 0x7b, 0x7c, + 0x7e, 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x7e, 0x7f, 0x80, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x80, 0x81, 0x81, 0x82, 0x82, 0x83, 0x82, 0x81, + 0x81, 0x80, 0x80, 0x80, 0x81, 0x81, 0x81, 0x81, 0x80, 0x80, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, 0x7e, 0x7d, 0x7d, 0x7d, 0x7d, 0x7c, + 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7e, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x83, 0x83, + 0x82, 0x82, 0x82, 0x82, 0x83, 0x83, 0x83, 0x83, 0x82, 0x81, 0x81, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7e, 0x7e, 0x7d, 0x7d, 0x7e, + 0x7e, 0x7d, 0x7d, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7d, 0x7d, 0x7d, + 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x80, 0x80, 0x80, 0x81, 0x81, 0x81, 0x81, 0x80, 0x80, 0x7f, 0x7f, + 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + }, + { // 7 + 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, + 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, + 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x80, + 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, + 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x80, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x80, + 0x81, 0x7f, 0x7e, 0x7f, 0x7f, 0x7f, 0x7e, 0x80, 0x7e, 0x82, 0x7d, + 0x85, 0x80, 0x7e, 0x82, 0x7f, 0x82, 0x80, 0x81, 0x82, 0x82, 0x7e, + 0x81, 0x7e, 0x80, 0x80, 0x7e, 0x7c, 0x7f, 0x7f, 0x7d, 0x82, 0x7d, + 0x81, 0x7e, 0x80, 0x7e, 0x7e, 0x7e, 0x7d, 0x81, 0x7d, 0x84, 0x7d, + 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x81, 0x7d, 0x82, 0x7d, 0x81, 0x7e, + 0x7f, 0x80, 0x7f, 0x80, 0x82, 0x81, 0x82, 0x81, 0x84, 0x7e, 0x7f, + 0x82, 0x7f, 0x80, 0x7f, 0x81, 0x7c, 0x81, 0x7d, 0x81, 0x7f, 0x7e, + 0x83, 0x81, 0x7e, 0x81, 0x7b, 0x80, 0x7f, 0x81, 0x83, 0x80, 0x7f, + 0x7c, 0x83, 0x7b, 0x82, 0x7d, 0x80, 0x7c, 0x81, 0x7f, 0x7f, 0x7e, + 0x7f, 0x7f, 0x80, 0x82, 0x7d, 0x7f, 0x7f, 0x7d, 0x7c, 0x81, 0x7a, + 0x81, 0x7e, 0x81, 0x7e, 0x80, 0x80, 0x80, 0x81, 0x81, 0x80, 0x80, + 0x7b, 0x82, 0x7f, 0x7f, 0x83, 0x7e, 0x7f, 0x7f, 0x81, 0x7f, 0x80, + 0x84, 0x80, 0x79, 0x82, 0x7c, 0x7d, 0x80, 0x83, 0x7a, 0x7e, 0x7f, + 0x7d, 0x81, 0x80, 0x7e, 0x7f, 0x7e, 0x7e, 0x82, 0x81, 0x81, 0x7f, + 0x81, 0x81, 0x80, 0x80, 0x84, 0x7c, 0x84, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x83, 0x83, 0x80, 0x81, 0x81, 0x7e, 0x80, 0x80, 0x79, 0x80, + 0x7c, 0x7f, 0x81, 0x81, 0x7b, 0x7d, 0x7f, 0x7d, 0x80, 0x82, 0x80, + 0x7d, 0x7d, 0x7d, 0x7d, 0x7b, 0x82, 0x7f, 0x7b, 0x83, 0x7a, 0x7f, + 0x7f, 0x81, 0x7c, 0x83, 0x80, 0x80, 0x81, 0x85, 0x7f, 0x7d, 0x84, + 0x7f, 0x7f, 0x80, 0x86, 0x79, 0x85, 0x7d, 0x83, 0x7e, 0x82, 0x80, + 0x86, 0x81, 0x83, 0x81, 0x80, 0x7e, 0x82, 0x82, 0x7c, 0x84, 0x7e, + 0x83, 0x7f, 0x87, 0x7d, 0x83, 0x82, 0x83, 0x7f, 0x86, 0x7e, 0x82, + 0x7f, 0x84, 0x7e, 0x82, 0x80, 0x83, 0x84, 0x80, 0x84, 0x7e, 0x82, + 0x7e, 0x85, 0x7c, 0x85, 0x7b, 0x7f, 0x80, 0x80, 0x7d, 0x84, 0x7e, + 0x80, 0x7f, 0x80, 0x7e, 0x7c, 0x82, 0x7a, 0x82, 0x7a, 0x80, 0x7b, + 0x7d, 0x7d, 0x7a, 0x84, 0x79, 0x7f, 0x7f, 0x7c, 0x7b, 0x82, 0x82, + 0x7e, 0x85, 0x7d, 0x7f, 0x7f, 0x86, 0x7d, 0x86, 0x83, 0x7d, 0x7f, + 0x85, 0x7a, 0x82, 0x83, 0x78, 0x83, 0x7f, 0x7c, 0x7f, 0x80, 0x77, + 0x81, 0x7e, 0x7c, 0x7c, 0x7f, 0x75, 0x7f, 0x78, 0x7b, 0x7c, 0x79, + 0x7b, 0x77, 0x81, 0x79, 0x81, 0x82, 0x7c, 0x7e, 0x81, 0x79, 0x86, + 0x79, 0x82, 0x7b, 0x7b, 0x7c, 0x79, 0x84, 0x77, 0x85, 0x7e, 0x7e, + 0x83, 0x80, 0x81, 0x83, 0x80, 0x83, 0x80, 0x7f, 0x81, 0x7b, 0x82, + 0x7d, 0x81, 0x80, 0x7e, 0x82, 0x7a, 0x82, 0x7f, 0x80, 0x82, 0x7d, + 0x82, 0x7a, 0x7e, 0x82, 0x79, 0x85, 0x7b, 0x7b, 0x81, 0x76, 0x86, + 0x7a, 0x82, 0x7e, 0x7e, 0x7f, 0x7e, 0x84, 0x7e, 0x87, 0x7d, 0x85, + 0x7e, 0x81, 0x84, 0x7c, 0x82, 0x7f, 0x7b, 0x80, 0x7d, 0x7e, 0x7c, + 0x81, 0x7f, 0x7f, 0x84, 0x7b, 0x85, 0x78, 0x87, 0x7e, 0x82, 0x83, + 0x7b, 0x82, 0x79, 0x82, 0x7f, 0x80, 0x7f, 0x82, 0x7a, 0x83, 0x81, + 0x81, 0x86, 0x7e, 0x84, 0x7c, 0x82, 0x7e, 0x81, 0x7e, 0x7e, 0x81, + 0x79, 0x84, 0x7b, 0x7f, 0x7c, 0x80, 0x7f, 0x7f, 0x84, 0x79, 0x85, + 0x79, 0x80, 0x85, 0x79, 0x83, 0x7e, 0x78, 0x80, 0x82, 0x7d, 0x7e, + 0x84, 0x79, 0x7c, 0x83, 0x7c, 0x7c, 0x7e, 0x80, 0x75, 0x87, 0x7d, + 0x81, 0x7e, 0x84, 0x7b, 0x81, 0x84, 0x7a, 0x86, 0x79, 0x87, 0x7a, + 0x87, 0x7f, 0x80, 0x7e, 0x84, 0x7d, 0x83, 0x82, 0x7b, 0x84, 0x7a, + 0x83, 0x80, 0x80, 0x7d, 0x7f, 0x7a, 0x7e, 0x7d, 0x80, 0x7f, 0x82, + 0x80, 0x7f, 0x81, 0x7f, 0x7b, 0x81, 0x7d, 0x7f, 0x82, 0x7e, 0x81, + 0x7f, 0x82, 0x82, 0x81, 0x7f, 0x80, 0x78, 0x7c, 0x7d, 0x77, 0x81, + 0x7c, 0x7e, 0x7f, 0x81, 0x7f, 0x80, 0x85, 0x7e, 0x8a, 0x80, 0x87, + 0x83, 0x7a, 0x85, 0x7a, 0x80, 0x83, 0x7b, 0x7f, 0x7c, 0x80, 0x80, + 0x85, 0x84, 0x84, 0x84, 0x7f, 0x81, 0x7c, 0x7c, 0x7b, 0x80, 0x7c, + 0x7f, 0x88, 0x70, 0x88, 0x7b, 0x7b, 0x8a, 0x80, 0x81, 0x7e, 0x86, + 0x71, 0x8b, 0x7f, 0x7b, 0x85, 0x7d, 0x72, 0x86, 0x74, 0x7d, 0x7e, + 0x82, 0x7b, 0x83, 0x83, 0x73, 0x89, 0x75, 0x89, 0x7c, 0x8c, 0x80, + 0x80, 0x83, 0x81, 0x7f, 0x86, 0x81, 0x7d, 0x7b, 0x80, 0x7a, 0x7d, + 0x86, 0x80, 0x7e, 0x8a, 0x7e, 0x7d, 0x83, 0x7a, 0x80, 0x7c, 0x8b, + 0x76, 0x85, 0x7f, 0x7b, 0x7f, 0x87, 0x7e, 0x82, 0x82, 0x7b, 0x7e, + 0x81, 0x7c, 0x85, 0x7b, 0x7f, 0x81, 0x77, 0x7e, 0x81, 0x77, 0x80, + 0x85, 0x7b, 0x84, 0x7e, 0x7f, 0x77, 0x84, 0x7c, 0x7d, 0x83, 0x7e, + 0x7d, 0x83, 0x86, 0x84, 0x83, 0x8e, 0x78, 0x86, 0x82, 0x7a, 0x7e, + 0x82, 0x74, 0x83, 0x7c, 0x79, 0x85, 0x75, 0x87, 0x79, 0x88, 0x81, + 0x81, 0x83, 0x80, 0x7d, 0x88, 0x7c, 0x86, 0x7f, 0x7f, 0x83, 0x7d, + 0x88, 0x7a, 0x85, 0x7b, 0x80, 0x7c, 0x7f, 0x7c, 0x7d, 0x7e, 0x7b, + 0x84, 0x7a, 0x82, 0x7f, 0x77, 0x80, 0x7e, 0x73, 0x84, 0x78, 0x7a, + 0x87, 0x7e, 0x87, 0x82, 0x88, 0x7e, 0x87, 0x83, 0x7f, 0x87, 0x7b, + 0x86, 0x7b, 0x82, 0x85, 0x7a, 0x85, 0x80, 0x79, 0x82, 0x7e, 0x76, + 0x86, 0x78, 0x81, 0x81, 0x80, 0x80, 0x81, 0x81, 0x7c, 0x88, 0x7a, + 0x87, 0x7b, 0x82, 0x7d, 0x81, 0x81, 0x7f, 0x80, 0x7c, 0x80, 0x78, + 0x81, 0x79, 0x7f, 0x7b, 0x84, 0x76, 0x87, 0x7d, 0x7b, 0x85, 0x7d, + 0x82, 0x7f, 0x88, 0x75, 0x87, 0x80, 0x7a, 0x87, 0x81, 0x7c, 0x85, + 0x7f, 0x7e, 0x84, 0x7e, 0x85, 0x7f, 0x83, 0x82, 0x81, 0x7e, 0x84, + 0x7c, 0x7e, 0x83, 0x79, 0x81, 0x79, 0x83, 0x79, 0x84, 0x7e, 0x85, + 0x79, 0x8b, 0x78, 0x7f, 0x87, 0x71, 0x8b, 0x73, 0x84, 0x7a, 0x80, + 0x7b, 0x85, 0x77, 0x82, 0x81, 0x76, 0x81, 0x80, 0x76, 0x85, 0x81, + 0x7a, 0x8d, 0x7d, 0x88, 0x86, 0x81, 0x87, 0x82, 0x7d, 0x83, 0x80, + 0x76, 0x88, 0x7d, 0x75, 0x90, 0x76, 0x7f, 0x86, 0x7e, 0x75, 0x8d, + 0x71, 0x82, 0x7f, 0x7c, 0x7e, 0x84, 0x7c, 0x83, 0x84, 0x79, 0x8a, + 0x75, 0x85, 0x79, 0x84, 0x75, 0x8b, 0x73, 0x8a, 0x79, 0x88, 0x7b, + 0x84, 0x80, 0x78, 0x87, 0x6f, 0x8a, 0x6e, 0x88, 0x76, 0x84, 0x7a, + 0x89, 0x7a, 0x88, 0x80, 0x81, 0x84, 0x81, 0x83, 0x81, 0x85, 0x7d, + 0x8c, 0x77, 0x8e, 0x77, 0x8b, 0x76, 0x8d, 0x71, 0x88, 0x79, 0x7c, + 0x7e, 0x7c, 0x7d, 0x77, 0x88, 0x6f, 0x8b, 0x75, 0x86, 0x79, 0x8a, + 0x75, 0x8d, 0x77, 0x88, 0x7a, 0x84, 0x7a, 0x82, 0x7a, 0x80, 0x7e, + 0x7a, 0x89, 0x73, 0x8c, 0x79, 0x85, 0x7d, 0x88, 0x76, 0x8a, 0x78, + 0x84, 0x77, 0x8c, 0x6f, 0x8f, 0x77, 0x82, 0x82, 0x80, 0x82, 0x7e, + 0x88, 0x77, 0x8e, 0x76, 0x8b, 0x7a, 0x88, 0x78, 0x88, 0x77, 0x84, + 0x7b, 0x7f, 0x7b, 0x82, 0x78, 0x82, 0x7e, 0x7e, 0x82, 0x7f, 0x80, + 0x81, 0x7e, 0x80, 0x7e, 0x7e, 0x81, 0x78, 0x85, 0x76, 0x86, 0x76, + 0x85, 0x78, 0x83, 0x7b, 0x80, 0x7e, 0x81, 0x7e, 0x82, 0x82, 0x7e, + 0x89, 0x7d, 0x84, 0x86, 0x7d, 0x86, 0x82, 0x81, 0x81, 0x82, 0x82, + 0x7e, 0x83, 0x80, 0x7c, 0x83, 0x7e, 0x7d, 0x82, 0x7d, 0x7d, 0x81, + 0x7d, 0x7b, 0x81, 0x78, 0x81, 0x76, 0x83, 0x73, 0x86, 0x75, 0x82, + 0x7d, 0x7e, 0x80, 0x7f, 0x7f, 0x81, 0x80, 0x7e, 0x84, 0x7b, 0x85, + 0x7c, 0x84, 0x7b, 0x87, 0x7b, 0x89, 0x7f, 0x89, 0x80, 0x8c, 0x81, + 0x85, 0x88, 0x7d, 0x86, 0x7e, 0x7c, 0x7c, 0x7a, 0x74, 0x79, 0x72, + 0x73, 0x71, 0x71, 0x6f, 0x75, 0x71, 0x79, 0x79, 0x7c, 0x84, 0x83, + 0x8d, 0x91, 0x95, 0x9c, 0x9f, 0xa0, 0xa3, 0xa2, 0x9c, 0x9c, 0x92, + 0x8b, 0x83, 0x77, 0x6f, 0x66, 0x5b, 0x5a, 0x50, 0x4d, 0x4f, 0x4b, + 0x50, 0x58, 0x59, 0x68, 0x72, 0x79, 0x8b, 0x92, 0x9b, 0xa9, 0xac, + 0xb5, 0xb8, 0xba, 0xbb, 0xb7, 0xb3, 0xad, 0xa3, 0x9a, 0x91, 0x81, + 0x7a, 0x6c, 0x62, 0x58, 0x55, 0x45, 0x4c, 0x3f, 0x41, 0x45, 0x41, + 0x4e, 0x52, 0x5f, 0x6c, 0x78, 0x88, 0x92, 0x9f, 0xaa, 0xb3, 0xb6, + 0xc1, 0xbc, 0xbe, 0xbb, 0xb2, 0xb0, 0xa2, 0x9d, 0x8e, 0x87, 0x79, + 0x73, 0x65, 0x63, 0x54, 0x55, 0x49, 0x47, 0x40, 0x43, 0x3d, 0x47, + 0x4f, 0x4f, 0x6a, 0x68, 0x82, 0x89, 0x9c, 0xa4, 0xb5, 0xb6, 0xc3, + 0xc4, 0xc4, 0xc3, 0xbe, 0xb6, 0xad, 0xa5, 0x96, 0x8e, 0x7f, 0x77, + 0x69, 0x63, 0x57, 0x53, 0x47, 0x44, 0x3c, 0x3b, 0x39, 0x3e, 0x47, + 0x4c, 0x5f, 0x67, 0x79, 0x86, 0x96, 0xa3, 0xb0, 0xb9, 0xc2, 0xc5, + 0xc7, 0xc6, 0xc1, 0xbb, 0xb0, 0xa9, 0x9a, 0x90, 0x83, 0x78, 0x6b, + 0x64, 0x5a, 0x54, 0x4a, 0x44, 0x3d, 0x3a, 0x38, 0x3e, 0x44, 0x4c, + 0x5b, 0x66, 0x73, 0x84, 0x91, 0xa0, 0xae, 0xb6, 0xc2, 0xc4, 0xca, + 0xc5, 0xc6, 0xba, 0xb5, 0xa7, 0x9e, 0x90, 0x85, 0x7a, 0x6e, 0x67, + 0x5c, 0x56, 0x4c, 0x46, 0x3c, 0x3e, 0x34, 0x40, 0x42, 0x48, 0x59, + 0x61, 0x6f, 0x83, 0x8c, 0x9f, 0xae, 0xb6, 0xc3, 0xc7, 0xcb, 0xc9, + 0xc8, 0xbc, 0xb6, 0xa9, 0x9e, 0x90, 0x86, 0x77, 0x6e, 0x63, 0x5c, + 0x51, 0x4c, 0x42, 0x3c, 0x3b, 0x34, 0x40, 0x41, 0x4b, 0x5a, 0x65, + 0x71, 0x87, 0x8e, 0xa4, 0xaf, 0xba, 0xc4, 0xc8, 0xcc, 0xc9, 0xc7, + 0xbc, 0xb5, 0xa7, 0x9d, 0x8d, 0x83, 0x75, 0x6c, 0x61, 0x5b, 0x50, + 0x4b, 0x42, 0x3c, 0x39, 0x35, 0x41, 0x3e, 0x4e, 0x58, 0x64, 0x73, + 0x85, 0x8f, 0xa4, 0xaf, 0xbb, 0xc6, 0xc8, 0xcf, 0xc9, 0xc8, 0xbc, + 0xb5, 0xa6, 0x9b, 0x8d, 0x82, 0x74, 0x6b, 0x5f, 0x59, 0x4f, 0x48, + 0x41, 0x3b, 0x36, 0x36, 0x41, 0x3e, 0x53, 0x58, 0x67, 0x77, 0x86, + 0x92, 0xa6, 0xb0, 0xbd, 0xc6, 0xc9, 0xce, 0xca, 0xc7, 0xbd, 0xb4, + 0xa7, 0x9b, 0x8c, 0x84, 0x73, 0x6d, 0x5f, 0x5a, 0x4e, 0x4b, 0x3d, + 0x3d, 0x32, 0x38, 0x40, 0x3b, 0x55, 0x56, 0x67, 0x77, 0x85, 0x91, + 0xaa, 0xaf, 0xc0, 0xc8, 0xca, 0xcf, 0xcc, 0xc6, 0xbe, 0xb3, 0xa5, + 0x99, 0x8c, 0x7f, 0x73, 0x69, 0x5d, 0x58, 0x4c, 0x47, 0x3d, 0x3b, + 0x2f, 0x41, 0x3a, 0x46, 0x58, 0x59, 0x6f, 0x7b, 0x87, 0x9a, 0xab, + 0xb2, 0xc4, 0xc4, 0xcc, 0xcb, 0xc9, 0xc3, 0xbb, 0xae, 0xa3, 0x94, + 0x8a, 0x7a, 0x72, 0x64, 0x5c, 0x54, 0x49, 0x43, 0x3b, 0x36, 0x32, + 0x42, 0x37, 0x50, 0x55, 0x5f, 0x73, 0x7e, 0x8a, 0xa1, 0xab, 0xb6, + 0xc4, 0xc4, 0xcc, 0xc9, 0xc8, 0xc0, 0xb8, 0xa9, 0xa0, 0x90, 0x86, + 0x77, 0x70, 0x60, 0x5c, 0x4f, 0x48, 0x3f, 0x3b, 0x33, 0x39, 0x41, + 0x3c, 0x56, 0x55, 0x67, 0x76, 0x83, 0x90, 0xa8, 0xac, 0xbd, 0xc5, + 0xc7, 0xce, 0xc9, 0xc7, 0xbd, 0xb4, 0xa5, 0x9b, 0x8c, 0x80, 0x74, + 0x6a, 0x5e, 0x58, 0x4c, 0x45, 0x3f, 0x38, 0x36, 0x40, 0x3c, 0x4a, + 0x56, 0x5b, 0x71, 0x7b, 0x8a, 0x9c, 0xa9, 0xb3, 0xc3, 0xc3, 0xcc, + 0xcb, 0xc7, 0xc3, 0xb8, 0xad, 0xa0, 0x94, 0x86, 0x7a, 0x70, 0x63, + 0x5b, 0x51, 0x48, 0x40, 0x3c, 0x33, 0x3b, 0x3d, 0x40, 0x52, 0x54, + 0x67, 0x74, 0x82, 0x91, 0xa3, 0xab, 0xbb, 0xc2, 0xc6, 0xcc, 0xc8, + 0xc6, 0xbd, 0xb4, 0xa8, 0x9b, 0x8e, 0x82, 0x75, 0x6c, 0x61, 0x57, + 0x4f, 0x45, 0x3e, 0x39, 0x34, 0x3e, 0x3b, 0x48, 0x52, 0x59, 0x6d, + 0x79, 0x87, 0x9b, 0xa7, 0xb3, 0xc0, 0xc3, 0xcb, 0xcb, 0xc8, 0xc4, + 0xba, 0xae, 0xa4, 0x95, 0x8b, 0x7c, 0x72, 0x67, 0x5e, 0x54, 0x4c, + 0x43, 0x3c, 0x38, 0x3a, 0x3f, 0x40, 0x50, 0x54, 0x62, 0x72, 0x7f, + 0x90, 0xa1, 0xab, 0xba, 0xc1, 0xc5, 0xcb, 0xc8, 0xc6, 0xbe, 0xb3, + 0xa8, 0x9c, 0x8e, 0x83, 0x75, 0x6b, 0x60, 0x57, 0x4d, 0x45, 0x3d, + 0x38, 0x38, 0x3d, 0x3f, 0x49, 0x54, 0x5c, 0x6e, 0x7a, 0x8b, 0x9c, + 0xa9, 0xb5, 0xc0, 0xc4, 0xc9, 0xca, 0xc5, 0xc2, 0xb5, 0xac, 0x9f, + 0x93, 0x86, 0x7a, 0x6f, 0x65, 0x5a, 0x53, 0x49, 0x40, 0x3d, 0x36, + 0x3f, 0x3d, 0x46, 0x51, 0x57, 0x67, 0x75, 0x83, 0x96, 0xa3, 0xb0, + 0xbc, 0xc2, 0xc7, 0xca, 0xc7, 0xc3, 0xbc, 0xaf, 0xa5, 0x97, 0x8a, + 0x7f, 0x72, 0x68, 0x5f, 0x53, 0x4c, 0x43, 0x3c, 0x38, 0x3b, 0x3e, + 0x42, 0x4f, 0x55, 0x62, 0x71, 0x7d, 0x8f, 0x9d, 0xab, 0xb6, 0xc1, + 0xc3, 0xc9, 0xc7, 0xc4, 0xbf, 0xb1, 0xa9, 0x9c, 0x8e, 0x83, 0x78, + 0x6b, 0x64, 0x58, 0x51, 0x47, 0x40, 0x3a, 0x39, 0x3e, 0x3f, 0x49, + 0x53, 0x5a, 0x6d, 0x78, 0x88, 0x99, 0xa6, 0xb2, 0xbe, 0xc2, 0xc8, + 0xc9, 0xc3, 0xc4, 0xb2, 0xae, 0x9e, 0x91, 0x86, 0x79, 0x6d, 0x67, + 0x58, 0x51, 0x4a, 0x3d, 0x3d, 0x38, 0x3c, 0x40, 0x48, 0x51, 0x5e, + 0x68, 0x7a, 0x87, 0x96, 0xa5, 0xb2, 0xbb, 0xc4, 0xc6, 0xc8, 0xc6, + 0xc0, 0xb7, 0xab, 0xa0, 0x92, 0x87, 0x79, 0x6f, 0x65, 0x5b, 0x51, + 0x4a, 0x40, 0x3c, 0x3a, 0x3d, 0x41, 0x49, 0x53, 0x5c, 0x6d, 0x78, + 0x88, 0x98, 0xa3, 0xb2, 0xbc, 0xc1, 0xc8, 0xc6, 0xc4, 0xc1, 0xb3, + 0xae, 0x9e, 0x93, 0x88, 0x79, 0x6e, 0x66, 0x58, 0x52, 0x49, 0x3f, + 0x3d, 0x38, 0x3d, 0x41, 0x49, 0x53, 0x5d, 0x6c, 0x7a, 0x88, 0x98, + 0xa6, 0xb2, 0xbc, 0xc4, 0xc4, 0xca, 0xc2, 0xc1, 0xb6, 0xab, 0xa0, + 0x91, 0x86, 0x79, 0x6d, 0x63, 0x5a, 0x4e, 0x49, 0x3d, 0x3b, 0x3a, + 0x3d, 0x42, 0x4d, 0x54, 0x61, 0x70, 0x7b, 0x8e, 0x9b, 0xa9, 0xb7, + 0xbe, 0xc6, 0xc8, 0xc7, 0xc6, 0xbc, 0xb5, 0xa9, 0x9b, 0x8f, 0x82, + 0x74, 0x6b, 0x60, 0x56, 0x4d, 0x43, 0x3d, 0x39, 0x3a, 0x40, 0x43, + 0x4f, 0x57, 0x63, 0x73, 0x80, 0x90, 0x9f, 0xac, 0xb8, 0xc1, 0xc6, + 0xc7, 0xc6, 0xc2, 0xb8, 0xb0, 0xa1, 0x95, 0x89, 0x7b, 0x71, 0x66, + 0x5c, 0x53, 0x49, 0x41, 0x3b, 0x3a, 0x3d, 0x40, 0x49, 0x53, 0x5d, + 0x6c, 0x7a, 0x88, 0x98, 0xa5, 0xb4, 0xbc, 0xc3, 0xc8, 0xc6, 0xc5, + 0xbe, 0xb2, 0xa9, 0x99, 0x8d, 0x82, 0x75, 0x6c, 0x61, 0x56, 0x4e, + 0x44, 0x3d, 0x3b, 0x3b, 0x40, 0x45, 0x4f, 0x57, 0x66, 0x74, 0x82, + 0x93, 0xa0, 0xae, 0xb9, 0xc0, 0xc7, 0xc7, 0xc5, 0xc2, 0xb5, 0xae, + 0x9e, 0x91, 0x87, 0x78, 0x6f, 0x67, 0x58, 0x53, 0x48, 0x40, 0x3e, + 0x3b, 0x40, 0x44, 0x4c, 0x56, 0x60, 0x6f, 0x7d, 0x8d, 0x9b, 0xa9, + 0xb4, 0xbc, 0xc4, 0xc4, 0xc6, 0xc2, 0xb8, 0xb0, 0xa2, 0x94, 0x8a, + 0x7b, 0x73, 0x66, 0x5d, 0x53, 0x4a, 0x43, 0x3d, 0x3d, 0x41, 0x44, + 0x4e, 0x57, 0x60, 0x71, 0x7d, 0x8d, 0x9c, 0xa9, 0xb4, 0xbd, 0xc1, + 0xc7, 0xc1, 0xc1, 0xb7, 0xab, 0xa3, 0x91, 0x88, 0x7c, 0x6f, 0x68, + 0x5d, 0x53, 0x4e, 0x43, 0x40, 0x3f, 0x41, 0x47, 0x4f, 0x58, 0x63, + 0x70, 0x7e, 0x8d, 0x9b, 0xa8, 0xb4, 0xbb, 0xc2, 0xc4, 0xc2, 0xbf, + 0xb8, 0xab, 0xa3, 0x92, 0x88, 0x7d, 0x71, 0x6a, 0x5f, 0x56, 0x4e, + 0x47, 0x3f, 0x40, 0x3f, 0x46, 0x4b, 0x56, 0x5e, 0x6c, 0x7a, 0x89, + 0x98, 0xa4, 0xb2, 0xb7, 0xc0, 0xc2, 0xc2, 0xbe, 0xbb, 0xae, 0xa7, + 0x98, 0x8c, 0x83, 0x76, 0x6e, 0x65, 0x5b, 0x53, 0x4c, 0x41, 0x43, + 0x3f, 0x45, 0x4a, 0x50, 0x5c, 0x64, 0x75, 0x80, 0x92, 0x9c, 0xab, + 0xb2, 0xba, 0xc0, 0xbf, 0xc0, 0xbc, 0xb2, 0xa9, 0x9f, 0x90, 0x89, + 0x7a, 0x72, 0x68, 0x5f, 0x56, 0x50, 0x46, 0x43, 0x44, 0x41, 0x4d, + 0x4c, 0x5a, 0x61, 0x6f, 0x7c, 0x8b, 0x98, 0xa4, 0xb0, 0xb5, 0xbf, + 0xbe, 0xbf, 0xbb, 0xb5, 0xaa, 0xa2, 0x93, 0x8a, 0x7d, 0x73, 0x6b, + 0x61, 0x5a, 0x53, 0x4c, 0x44, 0x48, 0x41, 0x4d, 0x4e, 0x57, 0x61, + 0x6a, 0x7a, 0x85, 0x95, 0x9e, 0xad, 0xaf, 0xbc, 0xba, 0xbe, 0xb9, + 0xb4, 0xad, 0xa1, 0x98, 0x8a, 0x82, 0x74, 0x6f, 0x62, 0x5f, 0x53, + 0x51, 0x45, 0x4a, 0x43, 0x4b, 0x51, 0x53, 0x64, 0x65, 0x7b, 0x80, + 0x93, 0x9a, 0xaa, 0xad, 0xb8, 0xb9, 0xb9, 0xbb, 0xb1, 0xaf, 0xa0, + 0x9a, 0x8b, 0x84, 0x76, 0x72, 0x64, 0x62, 0x57, 0x53, 0x4b, 0x49, + 0x4a, 0x48, 0x56, 0x52, 0x65, 0x66, 0x77, 0x80, 0x8e, 0x98, 0xa5, + 0xac, 0xb4, 0xb9, 0xb7, 0xbc, 0xb1, 0xb1, 0xa2, 0x9e, 0x8d, 0x87, + 0x79, 0x73, 0x68, 0x63, 0x58, 0x56, 0x4d, 0x4a, 0x4e, 0x47, 0x58, + 0x52, 0x63, 0x66, 0x74, 0x7c, 0x8d, 0x91, 0xa3, 0xa7, 0xaf, 0xb6, + 0xb3, 0xb8, 0xaf, 0xaf, 0xa1, 0x9d, 0x8c, 0x89, 0x78, 0x76, 0x69, + 0x65, 0x5a, 0x58, 0x4f, 0x4e, 0x4f, 0x4a, 0x58, 0x54, 0x64, 0x68, + 0x75, 0x7d, 0x8d, 0x91, 0xa3, 0xa4, 0xaf, 0xb2, 0xb2, 0xb7, 0xad, + 0xae, 0xa0, 0x9b, 0x8d, 0x87, 0x79, 0x76, 0x68, 0x66, 0x5a, 0x58, + 0x51, 0x4f, 0x52, 0x4d, 0x5b, 0x57, 0x65, 0x6b, 0x74, 0x7f, 0x8c, + 0x91, 0xa1, 0xa3, 0xad, 0xb0, 0xb1, 0xb1, 0xad, 0xaa, 0x9f, 0x9b, + 0x8c, 0x87, 0x7a, 0x74, 0x6a, 0x66, 0x5a, 0x5b, 0x51, 0x53, 0x53, + 0x50, 0x5c, 0x5a, 0x66, 0x6e, 0x75, 0x81, 0x8c, 0x92, 0xa1, 0xa3, + 0xab, 0xad, 0xb0, 0xab, 0xac, 0xa4, 0x9b, 0x98, 0x88, 0x85, 0x78, + 0x72, 0x6a, 0x64, 0x5c, 0x5c, 0x53, 0x57, 0x55, 0x55, 0x60, 0x5d, + 0x6a, 0x71, 0x77, 0x84, 0x8d, 0x92, 0xa0, 0xa2, 0xa7, 0xad, 0xa9, + 0xaa, 0xa8, 0x9e, 0x9c, 0x91, 0x88, 0x84, 0x76, 0x73, 0x6b, 0x62, + 0x61, 0x5a, 0x56, 0x5b, 0x54, 0x5c, 0x61, 0x60, 0x70, 0x72, 0x7b, + 0x87, 0x8c, 0x95, 0x9f, 0x9f, 0xa7, 0xa9, 0xa5, 0xa9, 0xa0, 0x9c, + 0x97, 0x8c, 0x86, 0x80, 0x75, 0x73, 0x68, 0x65, 0x61, 0x5b, 0x5a, + 0x5b, 0x5a, 0x5f, 0x65, 0x66, 0x74, 0x74, 0x80, 0x87, 0x8e, 0x96, + 0x9d, 0x9e, 0xa6, 0xa3, 0xa4, 0xa4, 0x9c, 0x9b, 0x92, 0x8b, 0x85, + 0x7e, 0x75, 0x74, 0x68, 0x68, 0x60, 0x60, 0x5d, 0x5f, 0x5d, 0x64, + 0x66, 0x6b, 0x74, 0x77, 0x81, 0x86, 0x8f, 0x93, 0x9b, 0x9b, 0xa3, + 0x9f, 0xa3, 0x9f, 0x9b, 0x98, 0x90, 0x8a, 0x84, 0x7d, 0x77, 0x72, + 0x6b, 0x69, 0x62, 0x62, 0x5f, 0x61, 0x61, 0x65, 0x69, 0x6d, 0x74, + 0x7a, 0x7f, 0x88, 0x8c, 0x92, 0x98, 0x9a, 0x9e, 0x9e, 0x9f, 0x9c, + 0x9a, 0x94, 0x90, 0x89, 0x84, 0x7d, 0x78, 0x72, 0x6e, 0x69, 0x66, + 0x65, 0x62, 0x64, 0x65, 0x67, 0x6c, 0x6f, 0x74, 0x7c, 0x7e, 0x88, + 0x8b, 0x90, 0x95, 0x98, 0x9a, 0x9d, 0x9b, 0x9a, 0x98, 0x92, 0x8f, + 0x89, 0x84, 0x7e, 0x78, 0x73, 0x70, 0x69, 0x69, 0x65, 0x65, 0x66, + 0x67, 0x69, 0x6d, 0x71, 0x76, 0x7c, 0x80, 0x86, 0x8b, 0x8f, 0x93, + 0x96, 0x97, 0x9a, 0x98, 0x97, 0x95, 0x91, 0x8d, 0x89, 0x83, 0x7f, + 0x79, 0x75, 0x71, 0x6d, 0x6b, 0x69, 0x68, 0x69, 0x69, 0x6b, 0x70, + 0x71, 0x77, 0x7b, 0x80, 0x85, 0x8a, 0x8e, 0x92, 0x94, 0x96, 0x97, + 0x96, 0x95, 0x92, 0x8f, 0x8a, 0x86, 0x81, 0x7d, 0x78, 0x74, 0x70, + 0x6e, 0x6c, 0x6b, 0x6b, 0x6b, 0x6d, 0x70, 0x72, 0x77, 0x7a, 0x7f, + 0x84, 0x88, 0x8c, 0x8f, 0x92, 0x94, 0x94, 0x94, 0x93, 0x91, 0x8e, + 0x8b, 0x86, 0x82, 0x7e, 0x7a, 0x77, 0x73, 0x71, 0x6f, 0x6f, 0x6d, + 0x6e, 0x6f, 0x71, 0x73, 0x76, 0x78, 0x7c, 0x7f, 0x82, 0x86, 0x88, + 0x8b, 0x8d, 0x8f, 0x8f, 0x90, 0x8f, 0x8e, 0x8c, 0x89, 0x87, 0x83, + 0x80, 0x7d, 0x7a, 0x77, 0x76, 0x73, 0x73, 0x72, 0x72, 0x73, 0x74, + 0x75, 0x78, 0x7a, 0x7c, 0x7f, 0x81, 0x84, 0x85, 0x88, 0x89, 0x8b, + 0x8c, 0x8c, 0x8c, 0x8a, 0x89, 0x87, 0x85, 0x82, 0x80, 0x7e, 0x7c, + 0x7a, 0x78, 0x77, 0x76, 0x76, 0x76, 0x76, 0x77, 0x79, 0x7a, 0x7c, + 0x7d, 0x7f, 0x81, 0x82, 0x83, 0x85, 0x85, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x85, 0x84, 0x83, 0x81, 0x81, 0x7f, 0x7e, 0x7d, 0x7c, 0x7c, + 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7c, 0x7d, 0x7d, 0x7e, 0x7f, 0x7f, + 0x81, 0x81, 0x82, 0x82, 0x83, 0x83, 0x83, 0x83, 0x83, 0x82, 0x82, + 0x81, 0x81, 0x80, 0x7f, 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, + 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x80, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, + 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x80, + 0x80, 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7f, + 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, + 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x80, + }, + { // 8 + 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, + 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, + 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x7f, + 0x80, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, + 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x80, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, 0x7e, 0x7f, 0x80, 0x80, 0x7f, + 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x7e, + 0x80, 0x80, 0x7f, 0x81, 0x80, 0x80, 0x81, 0x81, 0x80, 0x81, 0x81, + 0x81, 0x81, 0x82, 0x83, 0x91, 0x9c, 0x7a, 0x74, 0x82, 0x82, 0x97, + 0x94, 0x83, 0x74, 0x6d, 0x72, 0x7c, 0x80, 0x7a, 0x71, 0x6d, 0x6a, + 0x69, 0x72, 0x79, 0x7f, 0x82, 0x82, 0x7e, 0x7f, 0x82, 0x83, 0x82, + 0x84, 0x81, 0x83, 0x86, 0x86, 0x89, 0x89, 0x8a, 0x8a, 0x88, 0x85, + 0x80, 0x7b, 0x78, 0x71, 0x71, 0x6e, 0x6f, 0x70, 0x70, 0x71, 0x75, + 0x78, 0x78, 0x7d, 0x8a, 0xa1, 0xa7, 0xa7, 0x9a, 0x92, 0x8e, 0x91, + 0x95, 0x97, 0x94, 0x8b, 0x80, 0x71, 0x6a, 0x60, 0x5d, 0x59, 0x58, + 0x54, 0x56, 0x58, 0x6c, 0x83, 0xa0, 0xb8, 0xa7, 0x8f, 0x72, 0x6b, + 0x78, 0x88, 0x9b, 0xad, 0xa9, 0x98, 0x85, 0x79, 0x76, 0x78, 0x7e, + 0x81, 0x81, 0x77, 0x6e, 0x66, 0x62, 0x64, 0x60, 0x5c, 0x5a, 0x6e, + 0x7e, 0xa0, 0xb2, 0xa1, 0x91, 0x6f, 0x69, 0x78, 0x89, 0xa2, 0xaa, + 0xa9, 0x9d, 0x8c, 0x7c, 0x70, 0x77, 0x84, 0x90, 0x89, 0x7e, 0x6e, + 0x66, 0x5c, 0x5f, 0x62, 0x65, 0x5a, 0x66, 0x79, 0x90, 0xbf, 0xa9, + 0x95, 0x72, 0x5e, 0x73, 0x85, 0x9c, 0xb1, 0xa8, 0xa3, 0x8a, 0x7a, + 0x73, 0x71, 0x84, 0x8a, 0x8e, 0x7f, 0x72, 0x69, 0x61, 0x62, 0x66, + 0x60, 0x62, 0x4e, 0x66, 0x7e, 0x9f, 0xc8, 0xa3, 0x89, 0x68, 0x5c, + 0x77, 0x89, 0xa5, 0xb6, 0xa8, 0x9b, 0x7d, 0x74, 0x77, 0x7a, 0x8b, + 0x8c, 0x88, 0x77, 0x6f, 0x68, 0x69, 0x6e, 0x69, 0x62, 0x5b, 0x4b, + 0x67, 0x7f, 0xa0, 0xc7, 0xa2, 0x86, 0x60, 0x56, 0x7a, 0x90, 0xac, + 0xb5, 0xa4, 0x93, 0x76, 0x74, 0x7b, 0x80, 0x8e, 0x8d, 0x87, 0x75, + 0x6a, 0x6c, 0x70, 0x71, 0x6c, 0x5d, 0x5a, 0x4c, 0x63, 0x85, 0xa0, + 0xc6, 0xa9, 0x81, 0x5f, 0x57, 0x79, 0x98, 0xaf, 0xb4, 0x9f, 0x88, + 0x6f, 0x72, 0x80, 0x89, 0x92, 0x8a, 0x80, 0x6c, 0x69, 0x6b, 0x74, + 0x79, 0x72, 0x5e, 0x52, 0x44, 0x60, 0x88, 0xa0, 0xc9, 0xab, 0x84, + 0x5c, 0x51, 0x79, 0x9b, 0xb4, 0xb7, 0xa0, 0x86, 0x6f, 0x70, 0x82, + 0x8b, 0x92, 0x87, 0x7e, 0x6b, 0x68, 0x72, 0x79, 0x7d, 0x71, 0x5c, + 0x53, 0x4b, 0x5b, 0x8a, 0x9a, 0xc5, 0xb3, 0x80, 0x62, 0x4c, 0x74, + 0x9b, 0xb2, 0xb4, 0x9d, 0x85, 0x71, 0x71, 0x89, 0x90, 0x95, 0x88, + 0x78, 0x6d, 0x6a, 0x76, 0x7c, 0x7e, 0x72, 0x5e, 0x52, 0x52, 0x55, + 0x7f, 0x92, 0xb9, 0xc1, 0x89, 0x67, 0x4a, 0x6b, 0x9b, 0xb1, 0xb6, + 0x9f, 0x86, 0x76, 0x73, 0x88, 0x8f, 0x95, 0x88, 0x74, 0x6c, 0x68, + 0x79, 0x7d, 0x7e, 0x6f, 0x5c, 0x54, 0x4f, 0x52, 0x78, 0x91, 0xaf, + 0xc6, 0x92, 0x6c, 0x4f, 0x60, 0x94, 0xaf, 0xb9, 0xa2, 0x86, 0x75, + 0x73, 0x89, 0x95, 0x94, 0x89, 0x75, 0x6e, 0x6a, 0x7a, 0x82, 0x81, + 0x71, 0x5a, 0x51, 0x53, 0x56, 0x6c, 0x8a, 0x9e, 0xc6, 0xa1, 0x71, + 0x54, 0x54, 0x8d, 0xad, 0xb8, 0xa6, 0x88, 0x79, 0x73, 0x84, 0x96, + 0x94, 0x8d, 0x73, 0x6d, 0x6a, 0x77, 0x80, 0x80, 0x79, 0x63, 0x50, + 0x4b, 0x52, 0x65, 0x8d, 0x96, 0xbe, 0xae, 0x77, 0x5a, 0x4c, 0x81, + 0xac, 0xba, 0xad, 0x8a, 0x79, 0x73, 0x83, 0x9b, 0x94, 0x8d, 0x77, + 0x6e, 0x6e, 0x75, 0x84, 0x80, 0x78, 0x60, 0x56, 0x57, 0x5b, 0x57, + 0x7a, 0x8e, 0xb1, 0xc0, 0x83, 0x66, 0x4d, 0x71, 0xa0, 0xaf, 0xb1, + 0x95, 0x7c, 0x74, 0x7a, 0x93, 0x97, 0x8f, 0x7e, 0x6d, 0x71, 0x71, + 0x84, 0x7f, 0x78, 0x66, 0x59, 0x53, 0x59, 0x59, 0x76, 0x8c, 0xa1, + 0xc5, 0x91, 0x6e, 0x53, 0x65, 0x9b, 0xaf, 0xb2, 0x9c, 0x81, 0x7a, + 0x7a, 0x90, 0x99, 0x8f, 0x82, 0x6e, 0x71, 0x71, 0x82, 0x83, 0x79, + 0x6a, 0x58, 0x57, 0x5d, 0x59, 0x68, 0x84, 0x95, 0xbf, 0xa4, 0x75, + 0x5a, 0x5a, 0x8d, 0xaa, 0xb1, 0xa2, 0x88, 0x7b, 0x79, 0x89, 0x9b, + 0x94, 0x87, 0x73, 0x72, 0x72, 0x7c, 0x86, 0x7b, 0x6f, 0x5a, 0x5b, + 0x5d, 0x5b, 0x60, 0x7d, 0x8d, 0xba, 0xb0, 0x7e, 0x63, 0x52, 0x83, + 0xa3, 0xb5, 0xa8, 0x8d, 0x7c, 0x76, 0x85, 0x9a, 0x97, 0x8c, 0x75, + 0x6f, 0x71, 0x76, 0x88, 0x7e, 0x73, 0x5d, 0x5a, 0x58, 0x5c, 0x58, + 0x74, 0x89, 0xaa, 0xbb, 0x87, 0x6a, 0x50, 0x75, 0x9d, 0xb0, 0xab, + 0x90, 0x81, 0x77, 0x81, 0x9a, 0x99, 0x8d, 0x76, 0x6f, 0x76, 0x79, + 0x84, 0x7c, 0x70, 0x5c, 0x5a, 0x5d, 0x5f, 0x5d, 0x7a, 0x86, 0xb4, + 0xb5, 0x80, 0x63, 0x4e, 0x80, 0xa3, 0xb3, 0xa7, 0x8d, 0x7f, 0x78, + 0x87, 0x9b, 0x9a, 0x8b, 0x72, 0x70, 0x73, 0x7f, 0x82, 0x79, 0x6c, + 0x5e, 0x5c, 0x5b, 0x5a, 0x5b, 0x82, 0x91, 0xbb, 0xa6, 0x72, 0x5e, + 0x59, 0x8a, 0xa8, 0xb1, 0xa1, 0x87, 0x7a, 0x7a, 0x8e, 0x9d, 0x94, + 0x84, 0x6f, 0x73, 0x77, 0x86, 0x7f, 0x77, 0x64, 0x5a, 0x5d, 0x63, + 0x5d, 0x61, 0x7f, 0x99, 0xc1, 0x99, 0x72, 0x56, 0x69, 0x96, 0xa9, + 0xad, 0x97, 0x85, 0x7a, 0x81, 0x92, 0x9e, 0x92, 0x7b, 0x6c, 0x74, + 0x7d, 0x89, 0x83, 0x75, 0x5f, 0x5a, 0x5a, 0x65, 0x5b, 0x6c, 0x88, + 0xa1, 0xbf, 0x88, 0x69, 0x53, 0x74, 0x9d, 0xac, 0xa8, 0x8e, 0x81, + 0x7a, 0x83, 0x97, 0x9c, 0x8d, 0x76, 0x6c, 0x75, 0x7f, 0x88, 0x7b, + 0x70, 0x5f, 0x5e, 0x5d, 0x62, 0x59, 0x72, 0x88, 0xae, 0xb9, 0x85, + 0x64, 0x53, 0x7f, 0xa1, 0xb1, 0xa5, 0x8d, 0x7f, 0x78, 0x86, 0x99, + 0x9a, 0x89, 0x70, 0x6d, 0x77, 0x85, 0x85, 0x78, 0x6c, 0x5f, 0x5f, + 0x5c, 0x5d, 0x5b, 0x7f, 0x91, 0xb4, 0xa6, 0x76, 0x61, 0x5b, 0x8c, + 0xa3, 0xae, 0x9b, 0x86, 0x7d, 0x7b, 0x8d, 0x9c, 0x98, 0x81, 0x6c, + 0x6f, 0x7a, 0x87, 0x82, 0x76, 0x63, 0x5b, 0x5d, 0x64, 0x5d, 0x62, + 0x80, 0x92, 0xbe, 0x98, 0x77, 0x5a, 0x67, 0x96, 0xa7, 0xae, 0x96, + 0x86, 0x7c, 0x7e, 0x90, 0x9d, 0x93, 0x7e, 0x6e, 0x74, 0x7c, 0x87, + 0x7e, 0x77, 0x67, 0x5e, 0x58, 0x5f, 0x59, 0x6a, 0x89, 0x9f, 0xbb, + 0x8d, 0x6c, 0x55, 0x71, 0x9e, 0xaf, 0xaa, 0x8f, 0x80, 0x7a, 0x85, + 0x95, 0x9b, 0x8f, 0x77, 0x6d, 0x73, 0x7e, 0x85, 0x7c, 0x73, 0x62, + 0x60, 0x5c, 0x62, 0x58, 0x6b, 0x83, 0x9e, 0xb9, 0x8c, 0x6c, 0x56, + 0x75, 0x9d, 0xad, 0xa6, 0x8d, 0x82, 0x7c, 0x84, 0x95, 0x9a, 0x8e, + 0x79, 0x6f, 0x74, 0x7f, 0x86, 0x7b, 0x6e, 0x62, 0x61, 0x60, 0x65, + 0x55, 0x6a, 0x85, 0xa0, 0xb9, 0x89, 0x6c, 0x5a, 0x77, 0x9f, 0xab, + 0xa6, 0x8e, 0x83, 0x7b, 0x87, 0x95, 0x9c, 0x8d, 0x77, 0x71, 0x76, + 0x81, 0x84, 0x7b, 0x6f, 0x61, 0x63, 0x60, 0x65, 0x57, 0x65, 0x81, + 0x9e, 0xbb, 0x8e, 0x6f, 0x57, 0x73, 0x9b, 0xac, 0xab, 0x8e, 0x84, + 0x7a, 0x86, 0x94, 0x9b, 0x8e, 0x78, 0x70, 0x76, 0x83, 0x86, 0x7b, + 0x6c, 0x60, 0x63, 0x61, 0x65, 0x58, 0x64, 0x82, 0x9c, 0xba, 0x8d, + 0x70, 0x5b, 0x74, 0x9b, 0xa7, 0xa8, 0x8f, 0x87, 0x7c, 0x85, 0x94, + 0x9a, 0x8f, 0x77, 0x70, 0x75, 0x80, 0x85, 0x78, 0x6e, 0x64, 0x65, + 0x61, 0x63, 0x56, 0x63, 0x80, 0x98, 0xb6, 0x91, 0x75, 0x5b, 0x71, + 0x96, 0xa9, 0xab, 0x92, 0x86, 0x7b, 0x85, 0x93, 0x9c, 0x90, 0x79, + 0x70, 0x76, 0x7f, 0x83, 0x79, 0x70, 0x65, 0x62, 0x5f, 0x62, 0x5c, + 0x62, 0x7c, 0x92, 0xb4, 0x95, 0x76, 0x5d, 0x6f, 0x96, 0xa8, 0xab, + 0x92, 0x88, 0x7d, 0x86, 0x92, 0x9b, 0x91, 0x7b, 0x70, 0x74, 0x7f, + 0x84, 0x7b, 0x6f, 0x64, 0x64, 0x60, 0x64, 0x5b, 0x65, 0x7f, 0x91, + 0xb2, 0x92, 0x78, 0x60, 0x71, 0x97, 0xa8, 0xaa, 0x91, 0x86, 0x7d, + 0x89, 0x94, 0x9a, 0x8c, 0x79, 0x72, 0x76, 0x7f, 0x80, 0x78, 0x6d, + 0x63, 0x65, 0x61, 0x64, 0x59, 0x67, 0x7f, 0x97, 0xaf, 0x8e, 0x77, + 0x61, 0x79, 0x98, 0xa9, 0xa7, 0x90, 0x87, 0x80, 0x8b, 0x95, 0x97, + 0x8a, 0x78, 0x74, 0x79, 0x81, 0x7f, 0x75, 0x6b, 0x62, 0x64, 0x60, + 0x65, 0x59, 0x6f, 0x80, 0x9d, 0xab, 0x85, 0x72, 0x5f, 0x83, 0x9b, + 0xa9, 0x9e, 0x8c, 0x85, 0x81, 0x8e, 0x95, 0x97, 0x85, 0x75, 0x73, + 0x7b, 0x82, 0x7d, 0x72, 0x69, 0x64, 0x64, 0x63, 0x62, 0x5d, 0x76, + 0x7f, 0xa2, 0x9e, 0x85, 0x70, 0x66, 0x89, 0x9c, 0xa9, 0x98, 0x8b, + 0x82, 0x85, 0x8f, 0x97, 0x95, 0x82, 0x74, 0x75, 0x7b, 0x82, 0x79, + 0x6f, 0x66, 0x66, 0x61, 0x64, 0x5b, 0x67, 0x7c, 0x88, 0xa5, 0x8e, + 0x81, 0x68, 0x76, 0x91, 0xa2, 0xa5, 0x92, 0x8a, 0x83, 0x8b, 0x93, + 0x99, 0x8e, 0x7c, 0x75, 0x79, 0x81, 0x80, 0x75, 0x6c, 0x66, 0x66, + 0x62, 0x62, 0x5b, 0x72, 0x7d, 0x98, 0x9f, 0x84, 0x75, 0x67, 0x85, + 0x98, 0xa4, 0x9a, 0x8d, 0x88, 0x86, 0x90, 0x96, 0x94, 0x85, 0x77, + 0x76, 0x7a, 0x81, 0x7b, 0x76, 0x68, 0x63, 0x5f, 0x63, 0x61, 0x6a, + 0x79, 0x87, 0xa0, 0x8d, 0x7d, 0x69, 0x78, 0x91, 0xa0, 0x9d, 0x8e, + 0x89, 0x87, 0x8e, 0x95, 0x95, 0x8b, 0x7c, 0x76, 0x79, 0x7f, 0x7e, + 0x75, 0x6b, 0x67, 0x61, 0x61, 0x60, 0x65, 0x7a, 0x7f, 0x9c, 0x8f, + 0x85, 0x70, 0x73, 0x8c, 0x9a, 0xa2, 0x91, 0x8a, 0x84, 0x8c, 0x93, + 0x96, 0x8e, 0x7f, 0x77, 0x77, 0x7d, 0x7e, 0x79, 0x6f, 0x69, 0x63, + 0x60, 0x63, 0x64, 0x79, 0x7c, 0x96, 0x92, 0x84, 0x74, 0x70, 0x8a, + 0x99, 0xa4, 0x94, 0x8d, 0x85, 0x8b, 0x93, 0x93, 0x8f, 0x80, 0x79, + 0x78, 0x7c, 0x7c, 0x79, 0x6e, 0x65, 0x62, 0x64, 0x69, 0x67, 0x75, + 0x7b, 0x94, 0x93, 0x84, 0x74, 0x74, 0x8a, 0x97, 0x9e, 0x92, 0x8d, + 0x88, 0x8a, 0x90, 0x92, 0x8c, 0x81, 0x79, 0x79, 0x7d, 0x7a, 0x77, + 0x6f, 0x67, 0x61, 0x63, 0x64, 0x6d, 0x76, 0x7d, 0x93, 0x8d, 0x84, + 0x71, 0x77, 0x8b, 0x99, 0x9d, 0x93, 0x8c, 0x89, 0x8b, 0x90, 0x94, + 0x8a, 0x81, 0x7a, 0x7a, 0x7d, 0x7a, 0x76, 0x6e, 0x67, 0x60, 0x64, + 0x64, 0x6f, 0x79, 0x82, 0x93, 0x86, 0x80, 0x72, 0x7f, 0x8e, 0x9a, + 0x98, 0x90, 0x8c, 0x89, 0x90, 0x90, 0x93, 0x87, 0x80, 0x7a, 0x7c, + 0x7f, 0x7a, 0x74, 0x6c, 0x69, 0x64, 0x65, 0x66, 0x71, 0x7b, 0x85, + 0x8f, 0x85, 0x7c, 0x76, 0x80, 0x91, 0x9a, 0x98, 0x8f, 0x8a, 0x8a, + 0x91, 0x91, 0x8d, 0x83, 0x7f, 0x7c, 0x7d, 0x7d, 0x78, 0x71, 0x69, + 0x69, 0x66, 0x69, 0x68, 0x77, 0x7d, 0x89, 0x89, 0x80, 0x79, 0x78, + 0x89, 0x91, 0x97, 0x90, 0x8f, 0x8b, 0x8e, 0x8f, 0x8f, 0x8a, 0x84, + 0x82, 0x7f, 0x80, 0x78, 0x75, 0x6e, 0x6e, 0x69, 0x69, 0x66, 0x6a, + 0x77, 0x7e, 0x88, 0x80, 0x7d, 0x78, 0x7e, 0x8a, 0x91, 0x95, 0x8f, + 0x8c, 0x8c, 0x93, 0x93, 0x8f, 0x86, 0x86, 0x84, 0x82, 0x7e, 0x77, + 0x75, 0x71, 0x70, 0x69, 0x66, 0x65, 0x6f, 0x79, 0x80, 0x83, 0x7c, + 0x79, 0x77, 0x83, 0x8b, 0x8f, 0x90, 0x8d, 0x8d, 0x8e, 0x93, 0x90, + 0x8b, 0x88, 0x88, 0x85, 0x81, 0x7b, 0x77, 0x74, 0x71, 0x6d, 0x69, + 0x69, 0x6a, 0x74, 0x79, 0x80, 0x7f, 0x7c, 0x79, 0x7b, 0x87, 0x8d, + 0x91, 0x8d, 0x8d, 0x8c, 0x92, 0x94, 0x8f, 0x8b, 0x87, 0x89, 0x85, + 0x80, 0x78, 0x76, 0x75, 0x72, 0x6a, 0x69, 0x6c, 0x70, 0x75, 0x76, + 0x7d, 0x7c, 0x7b, 0x78, 0x7e, 0x88, 0x8f, 0x90, 0x8c, 0x8c, 0x8f, + 0x94, 0x91, 0x8c, 0x89, 0x89, 0x87, 0x82, 0x7d, 0x78, 0x75, 0x72, + 0x6e, 0x6b, 0x6e, 0x6f, 0x73, 0x75, 0x78, 0x7d, 0x7b, 0x7c, 0x7b, + 0x83, 0x8a, 0x90, 0x8e, 0x8c, 0x8f, 0x92, 0x91, 0x8a, 0x8a, 0x8a, + 0x8a, 0x82, 0x7c, 0x79, 0x77, 0x74, 0x6e, 0x6b, 0x6f, 0x73, 0x72, + 0x72, 0x72, 0x7a, 0x7d, 0x7e, 0x7b, 0x7f, 0x86, 0x8c, 0x8f, 0x8d, + 0x8e, 0x91, 0x93, 0x8c, 0x8a, 0x8a, 0x8b, 0x86, 0x80, 0x7b, 0x7a, + 0x77, 0x73, 0x6d, 0x6e, 0x72, 0x72, 0x72, 0x73, 0x77, 0x7b, 0x7d, + 0x7b, 0x7d, 0x83, 0x8b, 0x8b, 0x8c, 0x8e, 0x90, 0x8e, 0x8b, 0x8c, + 0x8d, 0x8b, 0x84, 0x81, 0x7d, 0x7c, 0x76, 0x74, 0x70, 0x72, 0x73, + 0x72, 0x6f, 0x70, 0x75, 0x7d, 0x81, 0x7d, 0x7b, 0x7f, 0x88, 0x8c, + 0x8f, 0x8c, 0x8c, 0x8c, 0x8e, 0x8c, 0x8a, 0x86, 0x85, 0x83, 0x80, + 0x7b, 0x76, 0x75, 0x74, 0x74, 0x72, 0x72, 0x70, 0x73, 0x76, 0x7c, + 0x7f, 0x7e, 0x7d, 0x81, 0x87, 0x8b, 0x8c, 0x8b, 0x8a, 0x8b, 0x8c, + 0x8a, 0x88, 0x85, 0x83, 0x80, 0x7d, 0x7c, 0x79, 0x76, 0x73, 0x72, + 0x72, 0x72, 0x75, 0x79, 0x7e, 0x7e, 0x7c, 0x7c, 0x82, 0x87, 0x8a, + 0x88, 0x88, 0x8b, 0x8c, 0x8b, 0x88, 0x87, 0x87, 0x85, 0x81, 0x7e, + 0x7d, 0x7b, 0x78, 0x75, 0x74, 0x74, 0x74, 0x74, 0x77, 0x7b, 0x7c, + 0x7c, 0x7c, 0x80, 0x83, 0x85, 0x87, 0x89, 0x89, 0x8a, 0x89, 0x88, + 0x88, 0x88, 0x84, 0x81, 0x7f, 0x7f, 0x7e, 0x7b, 0x78, 0x76, 0x76, + 0x77, 0x77, 0x77, 0x79, 0x7a, 0x7b, 0x7d, 0x80, 0x80, 0x82, 0x84, + 0x87, 0x87, 0x88, 0x87, 0x87, 0x88, 0x87, 0x85, 0x82, 0x81, 0x80, + 0x80, 0x7e, 0x7b, 0x79, 0x79, 0x79, 0x78, 0x78, 0x79, 0x7b, 0x7c, + 0x7c, 0x7c, 0x7e, 0x81, 0x83, 0x83, 0x84, 0x85, 0x86, 0x86, 0x86, + 0x85, 0x85, 0x84, 0x82, 0x80, 0x80, 0x80, 0x7f, 0x7c, 0x7a, 0x7a, + 0x7b, 0x7b, 0x7a, 0x7a, 0x7b, 0x7d, 0x7d, 0x7d, 0x7f, 0x81, 0x82, + 0x82, 0x83, 0x84, 0x85, 0x85, 0x84, 0x83, 0x84, 0x84, 0x82, 0x80, + 0x7f, 0x80, 0x80, 0x7e, 0x7c, 0x7b, 0x7c, 0x7c, 0x7c, 0x7b, 0x7c, + 0x7d, 0x7d, 0x7d, 0x7e, 0x80, 0x81, 0x81, 0x81, 0x82, 0x83, 0x84, + 0x83, 0x82, 0x82, 0x82, 0x82, 0x81, 0x80, 0x80, 0x7f, 0x7e, 0x7d, + 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7e, 0x7e, 0x7e, 0x7f, + 0x80, 0x80, 0x81, 0x81, 0x81, 0x82, 0x82, 0x82, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x80, 0x80, 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, + 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, 0x7f, 0x7e, 0x7e, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + }, + { // 9 + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, + 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, + 0x81, 0x81, 0x81, 0x81, 0x82, 0x82, 0x82, 0x82, 0x82, 0x81, 0x81, + 0x81, 0x80, 0x7f, 0x7f, 0x7e, 0x7d, 0x7d, 0x7c, 0x7c, 0x7b, 0x7b, + 0x7b, 0x7b, 0x7c, 0x7c, 0x7d, 0x7d, 0x7e, 0x7f, 0x7f, 0x80, 0x81, + 0x82, 0x82, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x82, 0x82, 0x81, + 0x80, 0x7f, 0x7e, 0x7e, 0x7d, 0x7d, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, + 0x7c, 0x7d, 0x7e, 0x7e, 0x7f, 0x80, 0x80, 0x81, 0x81, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x81, 0x81, 0x80, 0x80, 0x7f, 0x7f, + 0x7e, 0x7e, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7e, 0x7e, + 0x7e, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, + 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7e, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, + 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x81, 0x7f, 0x80, 0x7f, + 0x80, 0x80, 0x80, 0x81, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x81, + 0x7f, 0x7f, 0x7f, 0x7e, 0x7f, 0x7e, 0x80, 0x7f, 0x7f, 0x7f, 0x7d, + 0x7f, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7d, 0x7e, 0x7e, 0x7f, 0x80, + 0x7f, 0x81, 0x7d, 0x7f, 0x7e, 0x7f, 0x81, 0x80, 0x81, 0x80, 0x80, + 0x7f, 0x80, 0x82, 0x81, 0x82, 0x82, 0x80, 0x81, 0x7f, 0x81, 0x7f, + 0x82, 0x7f, 0x80, 0x7f, 0x7c, 0x7e, 0x7e, 0x7e, 0x7d, 0x7e, 0x7c, + 0x7c, 0x7c, 0x7d, 0x7b, 0x80, 0x7c, 0x7e, 0x7d, 0x7e, 0x7c, 0x7f, + 0x7f, 0x7f, 0x81, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x82, 0x80, 0x80, + 0x80, 0x81, 0x7e, 0x81, 0x80, 0x7f, 0x80, 0x80, 0x7e, 0x7f, 0x80, + 0x7e, 0x80, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x81, 0x80, 0x81, + 0x80, 0x81, 0x80, 0x81, 0x80, 0x80, 0x81, 0x80, 0x7f, 0x82, 0x7e, + 0x80, 0x80, 0x7e, 0x80, 0x7e, 0x80, 0x7d, 0x80, 0x7d, 0x80, 0x7e, + 0x80, 0x7d, 0x81, 0x7e, 0x7d, 0x81, 0x7c, 0x80, 0x7f, 0x7e, 0x80, + 0x7d, 0x81, 0x7e, 0x7d, 0x82, 0x7b, 0x81, 0x7f, 0x7f, 0x7d, 0x83, + 0x7e, 0x7d, 0x85, 0x7b, 0x82, 0x81, 0x7f, 0x7f, 0x81, 0x82, 0x7a, + 0x87, 0x7c, 0x82, 0x80, 0x82, 0x7d, 0x80, 0x85, 0x76, 0x8a, 0x79, + 0x83, 0x7d, 0x81, 0x80, 0x7a, 0x87, 0x78, 0x80, 0x83, 0x7a, 0x7f, + 0x82, 0x7b, 0x7d, 0x83, 0x7c, 0x7b, 0x86, 0x78, 0x7f, 0x81, 0x7d, + 0x7b, 0x83, 0x7c, 0x7c, 0x83, 0x7d, 0x7c, 0x83, 0x7e, 0x7c, 0x84, + 0x7b, 0x82, 0x7e, 0x83, 0x7c, 0x84, 0x7e, 0x82, 0x7e, 0x82, 0x82, + 0x7b, 0x87, 0x7c, 0x80, 0x82, 0x7f, 0x7e, 0x84, 0x7e, 0x7f, 0x80, + 0x83, 0x79, 0x84, 0x80, 0x79, 0x86, 0x7c, 0x7d, 0x83, 0x7d, 0x7d, + 0x80, 0x80, 0x79, 0x84, 0x7b, 0x7e, 0x80, 0x7c, 0x7f, 0x7e, 0x80, + 0x7b, 0x82, 0x7b, 0x81, 0x7d, 0x81, 0x7c, 0x81, 0x7c, 0x7f, 0x81, + 0x7c, 0x80, 0x82, 0x7b, 0x83, 0x7e, 0x7e, 0x82, 0x7c, 0x83, 0x7c, + 0x85, 0x7a, 0x85, 0x7e, 0x81, 0x81, 0x81, 0x82, 0x7d, 0x86, 0x7a, + 0x85, 0x7f, 0x80, 0x84, 0x7b, 0x83, 0x7e, 0x7e, 0x81, 0x7b, 0x82, + 0x7c, 0x7f, 0x7f, 0x7b, 0x81, 0x79, 0x84, 0x78, 0x84, 0x7a, 0x7e, + 0x80, 0x7a, 0x84, 0x7a, 0x84, 0x7d, 0x7c, 0x81, 0x7c, 0x7c, 0x82, + 0x7b, 0x82, 0x7b, 0x84, 0x78, 0x86, 0x79, 0x82, 0x81, 0x7f, 0x80, + 0x7f, 0x86, 0x75, 0x8c, 0x7b, 0x81, 0x84, 0x7d, 0x81, 0x81, 0x7b, + 0x83, 0x7d, 0x82, 0x7d, 0x83, 0x82, 0x7c, 0x84, 0x7e, 0x80, 0x82, + 0x7b, 0x89, 0x78, 0x83, 0x7f, 0x7e, 0x80, 0x7b, 0x87, 0x75, 0x88, + 0x75, 0x82, 0x7d, 0x7c, 0x80, 0x82, 0x7e, 0x7f, 0x84, 0x7b, 0x81, + 0x7f, 0x80, 0x7f, 0x81, 0x80, 0x7b, 0x86, 0x76, 0x85, 0x7b, 0x7f, + 0x83, 0x77, 0x84, 0x7a, 0x80, 0x7a, 0x88, 0x78, 0x88, 0x7c, 0x86, + 0x7c, 0x84, 0x80, 0x83, 0x82, 0x7f, 0x88, 0x7a, 0x8a, 0x7c, 0x85, + 0x80, 0x84, 0x78, 0x88, 0x7a, 0x7e, 0x84, 0x7b, 0x81, 0x7c, 0x80, + 0x7c, 0x7c, 0x80, 0x7b, 0x80, 0x7a, 0x7f, 0x7c, 0x7c, 0x84, 0x7b, + 0x85, 0x7f, 0x81, 0x7c, 0x85, 0x7a, 0x86, 0x7f, 0x82, 0x82, 0x7f, + 0x81, 0x7f, 0x80, 0x7e, 0x84, 0x7b, 0x81, 0x7f, 0x7a, 0x80, 0x80, + 0x7a, 0x88, 0x7a, 0x7f, 0x81, 0x7a, 0x7c, 0x82, 0x78, 0x80, 0x7f, + 0x7a, 0x7f, 0x7a, 0x7c, 0x81, 0x75, 0x80, 0x82, 0x73, 0x82, 0x7d, + 0x7a, 0x7d, 0x84, 0x77, 0x84, 0x7a, 0x7e, 0x81, 0x7a, 0x7c, 0x84, + 0x7a, 0x80, 0x86, 0x7a, 0x84, 0x82, 0x7b, 0x84, 0x82, 0x78, 0x8a, + 0x78, 0x7e, 0x85, 0x76, 0x82, 0x80, 0x7c, 0x7f, 0x85, 0x76, 0x82, + 0x83, 0x73, 0x8d, 0x7a, 0x7d, 0x89, 0x76, 0x81, 0x7d, 0x7e, 0x7c, + 0x7d, 0x83, 0x76, 0x85, 0x75, 0x89, 0x77, 0x81, 0x88, 0x76, 0x87, + 0x7d, 0x80, 0x7f, 0x85, 0x7a, 0x84, 0x84, 0x72, 0x89, 0x7f, 0x6f, + 0x8e, 0x73, 0x7a, 0x82, 0x79, 0x78, 0x87, 0x76, 0x80, 0x86, 0x77, + 0x85, 0x82, 0x7c, 0x86, 0x81, 0x7b, 0x8c, 0x74, 0x89, 0x7b, 0x81, + 0x81, 0x7d, 0x81, 0x7c, 0x84, 0x75, 0x8b, 0x7b, 0x7c, 0x8b, 0x7c, + 0x7e, 0x87, 0x80, 0x7c, 0x8b, 0x78, 0x84, 0x80, 0x78, 0x84, 0x73, + 0x83, 0x73, 0x80, 0x76, 0x7b, 0x78, 0x79, 0x80, 0x75, 0x87, 0x78, + 0x83, 0x7c, 0x85, 0x77, 0x87, 0x7a, 0x80, 0x81, 0x7e, 0x7f, 0x7f, + 0x82, 0x7b, 0x8b, 0x76, 0x8e, 0x7c, 0x83, 0x84, 0x82, 0x7e, 0x85, + 0x7e, 0x7c, 0x85, 0x77, 0x83, 0x7d, 0x80, 0x7a, 0x87, 0x77, 0x86, + 0x7f, 0x7c, 0x89, 0x73, 0x8c, 0x74, 0x84, 0x7e, 0x7a, 0x85, 0x76, + 0x88, 0x76, 0x88, 0x7b, 0x81, 0x86, 0x79, 0x89, 0x7d, 0x82, 0x80, + 0x84, 0x7a, 0x81, 0x81, 0x74, 0x84, 0x77, 0x79, 0x7c, 0x77, 0x77, + 0x78, 0x77, 0x76, 0x77, 0x77, 0x78, 0x76, 0x79, 0x7c, 0x77, 0x82, + 0x82, 0x80, 0x8e, 0x88, 0x91, 0x91, 0x97, 0x98, 0x98, 0xa0, 0x98, + 0x9b, 0x9a, 0x93, 0x8f, 0x8b, 0x80, 0x7c, 0x72, 0x6e, 0x62, 0x5f, + 0x5b, 0x50, 0x57, 0x4c, 0x54, 0x51, 0x56, 0x58, 0x60, 0x66, 0x6e, + 0x7c, 0x7d, 0x94, 0x91, 0xa3, 0xa8, 0xae, 0xb9, 0xb6, 0xbe, 0xb8, + 0xb7, 0xb1, 0xab, 0x9e, 0x98, 0x90, 0x80, 0x80, 0x71, 0x70, 0x69, + 0x66, 0x64, 0x5c, 0x5f, 0x57, 0x56, 0x4f, 0x54, 0x47, 0x4e, 0x4d, + 0x49, 0x55, 0x58, 0x62, 0x6d, 0x84, 0x87, 0xa2, 0xaa, 0xb4, 0xc3, + 0xc3, 0xc9, 0xc4, 0xc3, 0xb4, 0xb0, 0x9e, 0x97, 0x88, 0x7c, 0x7a, + 0x6d, 0x6d, 0x6e, 0x6b, 0x6c, 0x74, 0x6c, 0x72, 0x6d, 0x68, 0x66, + 0x5d, 0x59, 0x55, 0x4e, 0x48, 0x4f, 0x47, 0x52, 0x63, 0x60, 0x82, + 0x86, 0x98, 0xaf, 0xaf, 0xc5, 0xc4, 0xc8, 0xc8, 0xbf, 0xb4, 0xa9, + 0x99, 0x89, 0x82, 0x70, 0x6f, 0x67, 0x66, 0x65, 0x6f, 0x70, 0x72, + 0x86, 0x71, 0x87, 0x7b, 0x73, 0x77, 0x65, 0x61, 0x5a, 0x50, 0x46, + 0x4b, 0x44, 0x4a, 0x61, 0x61, 0x77, 0x94, 0x8d, 0xb4, 0xb7, 0xbd, + 0xce, 0xc5, 0xc4, 0xbf, 0xb3, 0xa1, 0x9e, 0x83, 0x80, 0x76, 0x66, + 0x6a, 0x62, 0x64, 0x6e, 0x71, 0x7e, 0x83, 0x86, 0x89, 0x82, 0x80, + 0x76, 0x6e, 0x66, 0x5e, 0x51, 0x50, 0x47, 0x3d, 0x49, 0x48, 0x4e, + 0x6d, 0x73, 0x84, 0xa4, 0xa4, 0xb9, 0xc4, 0xc4, 0xc8, 0xc7, 0xbb, + 0xb6, 0xa6, 0x97, 0x8b, 0x7a, 0x72, 0x6c, 0x66, 0x66, 0x69, 0x69, + 0x75, 0x7a, 0x81, 0x8c, 0x8b, 0x8c, 0x90, 0x81, 0x7f, 0x74, 0x67, + 0x63, 0x57, 0x52, 0x4c, 0x49, 0x43, 0x47, 0x4e, 0x52, 0x61, 0x7f, + 0x78, 0x9f, 0xae, 0xa6, 0xc9, 0xbc, 0xbf, 0xc3, 0xb8, 0xad, 0xa8, + 0x97, 0x89, 0x82, 0x73, 0x71, 0x6b, 0x69, 0x71, 0x71, 0x77, 0x80, + 0x82, 0x89, 0x8f, 0x8e, 0x8d, 0x8b, 0x7d, 0x76, 0x6f, 0x5e, 0x5d, + 0x55, 0x53, 0x51, 0x4b, 0x52, 0x4d, 0x4e, 0x63, 0x56, 0x75, 0x89, + 0x75, 0xb1, 0xa1, 0xad, 0xc7, 0xb5, 0xc1, 0xbc, 0xb5, 0xa5, 0xa5, + 0x90, 0x82, 0x82, 0x6f, 0x72, 0x70, 0x70, 0x75, 0x78, 0x7f, 0x85, + 0x87, 0x8c, 0x8f, 0x8b, 0x88, 0x87, 0x79, 0x75, 0x6e, 0x63, 0x62, + 0x5e, 0x5b, 0x5e, 0x5d, 0x59, 0x5e, 0x58, 0x54, 0x5c, 0x59, 0x64, + 0x89, 0x74, 0x9b, 0xb0, 0x99, 0xc4, 0xb8, 0xb7, 0xc0, 0xae, 0xa5, + 0x9f, 0x93, 0x81, 0x7e, 0x77, 0x6c, 0x72, 0x71, 0x76, 0x7c, 0x81, + 0x88, 0x8b, 0x8d, 0x8a, 0x85, 0x83, 0x79, 0x76, 0x74, 0x71, 0x6b, + 0x69, 0x6c, 0x67, 0x6c, 0x65, 0x68, 0x66, 0x63, 0x5e, 0x57, 0x5a, + 0x5c, 0x4f, 0x7d, 0x7a, 0x81, 0xb7, 0x9e, 0xb8, 0xc3, 0xbc, 0xbe, + 0xb5, 0xab, 0x97, 0x91, 0x7d, 0x70, 0x76, 0x6a, 0x6e, 0x77, 0x7a, + 0x84, 0x86, 0x8e, 0x90, 0x8d, 0x8e, 0x83, 0x79, 0x74, 0x6e, 0x69, + 0x6f, 0x6c, 0x71, 0x77, 0x71, 0x79, 0x74, 0x71, 0x71, 0x65, 0x66, + 0x54, 0x5a, 0x4a, 0x50, 0x59, 0x5d, 0x92, 0x7a, 0xb0, 0xbb, 0xad, + 0xca, 0xb7, 0xbb, 0xae, 0x9f, 0x93, 0x7e, 0x7e, 0x6e, 0x6f, 0x78, + 0x78, 0x85, 0x89, 0x91, 0x93, 0x91, 0x92, 0x8a, 0x82, 0x79, 0x71, + 0x69, 0x64, 0x6c, 0x6b, 0x78, 0x7a, 0x80, 0x7f, 0x7f, 0x7d, 0x73, + 0x6e, 0x62, 0x5a, 0x5b, 0x50, 0x51, 0x49, 0x50, 0x64, 0x6f, 0x9c, + 0x97, 0xbc, 0xc3, 0xb6, 0xc2, 0xab, 0xa6, 0x99, 0x8a, 0x83, 0x74, + 0x7c, 0x79, 0x7a, 0x89, 0x87, 0x92, 0x93, 0x93, 0x8d, 0x85, 0x80, + 0x78, 0x71, 0x71, 0x69, 0x6c, 0x6f, 0x75, 0x7b, 0x80, 0x89, 0x82, + 0x80, 0x7d, 0x73, 0x6c, 0x6b, 0x64, 0x60, 0x57, 0x64, 0x5b, 0x61, + 0x5f, 0x5b, 0x6a, 0x7b, 0x9e, 0x96, 0xb3, 0xb3, 0xae, 0xaf, 0xa0, + 0x9d, 0x8e, 0x8c, 0x88, 0x82, 0x8a, 0x87, 0x8c, 0x8d, 0x8c, 0x8e, + 0x86, 0x8b, 0x80, 0x7c, 0x7c, 0x74, 0x74, 0x73, 0x78, 0x79, 0x76, + 0x7c, 0x7e, 0x80, 0x7e, 0x77, 0x78, 0x73, 0x6e, 0x69, 0x68, 0x6b, + 0x6a, 0x6e, 0x67, 0x66, 0x66, 0x65, 0x5a, 0x53, 0x65, 0x8b, 0x96, + 0x9a, 0xb7, 0xb5, 0xaf, 0xa4, 0xa3, 0x98, 0x89, 0x89, 0x88, 0x85, + 0x84, 0x8b, 0x91, 0x8f, 0x90, 0x8b, 0x86, 0x85, 0x7b, 0x79, 0x76, + 0x78, 0x77, 0x79, 0x78, 0x7c, 0x7e, 0x7d, 0x7a, 0x7b, 0x75, 0x76, + 0x70, 0x6f, 0x72, 0x70, 0x71, 0x71, 0x73, 0x6f, 0x6f, 0x68, 0x63, + 0x62, 0x61, 0x5f, 0x5d, 0x57, 0x92, 0xa1, 0xa6, 0xb8, 0xb9, 0xbc, + 0x97, 0x97, 0x90, 0x88, 0x81, 0x82, 0x91, 0x89, 0x92, 0x93, 0x94, + 0x96, 0x85, 0x86, 0x7a, 0x74, 0x73, 0x71, 0x74, 0x77, 0x7e, 0x7d, + 0x80, 0x7d, 0x7c, 0x78, 0x70, 0x7a, 0x79, 0x7a, 0x76, 0x75, 0x78, + 0x73, 0x73, 0x70, 0x70, 0x6b, 0x65, 0x5f, 0x5f, 0x61, 0x5a, 0x55, + 0x5e, 0x8a, 0xae, 0xa8, 0xaf, 0xb3, 0xb2, 0x98, 0x82, 0x86, 0x82, + 0x89, 0x85, 0x92, 0x9a, 0x98, 0x98, 0x91, 0x90, 0x84, 0x79, 0x73, + 0x73, 0x78, 0x79, 0x7d, 0x81, 0x83, 0x80, 0x7b, 0x77, 0x72, 0x73, + 0x73, 0x7b, 0x79, 0x7d, 0x83, 0x81, 0x84, 0x7a, 0x7c, 0x75, 0x71, + 0x70, 0x6d, 0x70, 0x6f, 0x6a, 0x69, 0x6b, 0x6e, 0x6f, 0x6c, 0x66, + 0x6e, 0x81, 0x91, 0xa5, 0xa8, 0xab, 0xa5, 0x9b, 0x91, 0x88, 0x8a, + 0x8a, 0x8e, 0x8f, 0x92, 0x94, 0x8f, 0x8a, 0x84, 0x82, 0x7b, 0x74, + 0x77, 0x7b, 0x7f, 0x7e, 0x7f, 0x7e, 0x7c, 0x78, 0x77, 0x74, 0x76, + 0x77, 0x81, 0x87, 0x88, 0x82, 0x77, 0x75, 0x6f, 0x70, 0x6c, 0x6f, + 0x71, 0x6f, 0x66, 0x62, 0x66, 0x6a, 0x64, 0x5a, 0x60, 0x74, 0xa3, + 0xb4, 0xb1, 0xa4, 0x9f, 0x9d, 0x85, 0x79, 0x7b, 0x90, 0x9a, 0x99, + 0x93, 0x96, 0x98, 0x90, 0x83, 0x77, 0x77, 0x79, 0x79, 0x79, 0x7c, + 0x82, 0x82, 0x7c, 0x79, 0x76, 0x75, 0x74, 0x76, 0x76, 0x7a, 0x7c, + 0x7f, 0x82, 0x7f, 0x84, 0x7f, 0x82, 0x81, 0x7e, 0x7b, 0x71, 0x75, + 0x74, 0x7a, 0x78, 0x74, 0x77, 0x71, 0x6e, 0x65, 0x66, 0x6b, 0x6e, + 0x6f, 0x6e, 0x7c, 0x90, 0xa8, 0xb1, 0xaa, 0x9d, 0x8f, 0x89, 0x83, + 0x82, 0x88, 0x92, 0x99, 0x99, 0x92, 0x8c, 0x85, 0x80, 0x7d, 0x7b, + 0x7c, 0x7b, 0x7e, 0x7f, 0x7f, 0x7c, 0x7a, 0x79, 0x79, 0x77, 0x74, + 0x76, 0x78, 0x7c, 0x7b, 0x7c, 0x81, 0x86, 0x88, 0x82, 0x7c, 0x75, + 0x73, 0x70, 0x72, 0x77, 0x79, 0x79, 0x71, 0x6e, 0x68, 0x69, 0x6b, + 0x69, 0x64, 0x60, 0x75, 0x9a, 0xb8, 0xba, 0xa5, 0x8f, 0x86, 0x83, + 0x7f, 0x7d, 0x85, 0x95, 0xa1, 0x9f, 0x93, 0x88, 0x84, 0x83, 0x7d, + 0x77, 0x76, 0x7d, 0x83, 0x83, 0x7f, 0x7c, 0x7b, 0x7c, 0x7a, 0x76, + 0x73, 0x74, 0x7b, 0x7d, 0x7c, 0x77, 0x77, 0x79, 0x7a, 0x7a, 0x79, + 0x7b, 0x7d, 0x83, 0x87, 0x8c, 0x8a, 0x84, 0x7c, 0x74, 0x73, 0x74, + 0x7b, 0x7e, 0x7f, 0x7c, 0x76, 0x6f, 0x69, 0x6a, 0x6f, 0x72, 0x72, + 0x6e, 0x75, 0x87, 0xa5, 0xb4, 0xac, 0x95, 0x7e, 0x7c, 0x7d, 0x84, + 0x83, 0x8a, 0x94, 0x9b, 0x99, 0x8b, 0x7f, 0x76, 0x79, 0x7b, 0x7c, + 0x7c, 0x7c, 0x80, 0x82, 0x81, 0x7c, 0x78, 0x77, 0x78, 0x79, 0x78, + 0x77, 0x78, 0x79, 0x7d, 0x7d, 0x7b, 0x7a, 0x7d, 0x80, 0x80, 0x7c, + 0x7c, 0x7e, 0x81, 0x82, 0x83, 0x8b, 0x8e, 0x8c, 0x7a, 0x6f, 0x6c, + 0x7a, 0x86, 0x89, 0x84, 0x7c, 0x7b, 0x77, 0x75, 0x6d, 0x6c, 0x6e, + 0x76, 0x78, 0x72, 0x69, 0x6f, 0x8d, 0xae, 0xbc, 0xa6, 0x85, 0x6f, + 0x73, 0x82, 0x89, 0x8a, 0x86, 0x8d, 0x94, 0x95, 0x8a, 0x7a, 0x75, + 0x76, 0x7e, 0x7f, 0x7c, 0x7a, 0x7a, 0x7f, 0x82, 0x81, 0x7c, 0x76, + 0x76, 0x79, 0x7c, 0x7a, 0x78, 0x78, 0x7b, 0x7f, 0x80, 0x7f, 0x7b, + 0x7a, 0x7c, 0x7e, 0x7f, 0x7f, 0x80, 0x81, 0x82, 0x82, 0x80, 0x7f, + 0x7f, 0x81, 0x81, 0x80, 0x7f, 0x80, 0x83, 0x83, 0x83, 0x82, 0x81, + 0x82, 0x82, 0x83, 0x81, 0x81, 0x80, 0x85, 0x8a, 0x8a, 0x89, 0x82, + 0x7e, 0x76, 0x76, 0x75, 0x7a, 0x7e, 0x7f, 0x7e, 0x79, 0x75, 0x70, + 0x6f, 0x6e, 0x6f, 0x71, 0x75, 0x76, 0x75, 0x71, 0x78, 0x87, 0x9d, + 0xa7, 0xa1, 0x8f, 0x7a, 0x74, 0x79, 0x85, 0x8c, 0x8c, 0x8a, 0x8a, + 0x8d, 0x8b, 0x85, 0x7a, 0x74, 0x74, 0x7a, 0x81, 0x83, 0x83, 0x80, + 0x7f, 0x7f, 0x7e, 0x7b, 0x76, 0x71, 0x74, 0x79, 0x7f, 0x81, 0x7f, + 0x7d, 0x7a, 0x7a, 0x7c, 0x7c, 0x7d, 0x7b, 0x7d, 0x7f, 0x82, 0x83, + 0x81, 0x7f, 0x7d, 0x7e, 0x80, 0x82, 0x81, 0x7f, 0x7e, 0x80, 0x82, + 0x84, 0x82, 0x81, 0x7f, 0x7f, 0x7f, 0x82, 0x80, 0x81, 0x7e, 0x81, + 0x80, 0x81, 0x7e, 0x83, 0x80, 0x83, 0x7f, 0x87, 0x93, 0x94, 0x92, + 0x76, 0x6e, 0x64, 0x77, 0x7f, 0x89, 0x82, 0x78, 0x6e, 0x66, 0x6d, + 0x6c, 0x73, 0x71, 0x70, 0x6e, 0x69, 0x76, 0x8c, 0xa8, 0xb7, 0xa8, + 0x8f, 0x6f, 0x69, 0x6e, 0x86, 0x93, 0x99, 0x91, 0x88, 0x88, 0x87, + 0x89, 0x7e, 0x76, 0x6d, 0x70, 0x79, 0x85, 0x8b, 0x87, 0x80, 0x79, + 0x79, 0x7a, 0x7a, 0x75, 0x72, 0x73, 0x7a, 0x82, 0x86, 0x84, 0x7d, + 0x77, 0x76, 0x78, 0x7c, 0x7e, 0x7d, 0x7d, 0x7d, 0x80, 0x83, 0x84, + 0x81, 0x7e, 0x7b, 0x7c, 0x7f, 0x81, 0x81, 0x80, 0x7e, 0x7e, 0x7f, + 0x81, 0x82, 0x81, 0x81, 0x80, 0x81, 0x80, 0x82, 0x82, 0x82, 0x82, + 0x80, 0x81, 0x81, 0x82, 0x82, 0x81, 0x7f, 0x7e, 0x7f, 0x80, 0x82, + 0x82, 0x80, 0x7f, 0x7e, 0x7f, 0x80, 0x81, 0x80, 0x7e, 0x7e, 0x7f, + 0x84, 0x86, 0x89, 0x86, 0x81, 0x7b, 0x78, 0x7b, 0x7d, 0x82, 0x81, + 0x80, 0x7b, 0x79, 0x76, 0x75, 0x76, 0x75, 0x76, 0x75, 0x76, 0x75, + 0x77, 0x76, 0x76, 0x74, 0x74, 0x79, 0x84, 0x95, 0xa2, 0xa8, 0x9c, + 0x8c, 0x78, 0x72, 0x75, 0x82, 0x8e, 0x92, 0x8f, 0x88, 0x85, 0x83, + 0x83, 0x80, 0x7c, 0x76, 0x73, 0x74, 0x7a, 0x81, 0x86, 0x84, 0x80, + 0x79, 0x75, 0x74, 0x76, 0x79, 0x7b, 0x7c, 0x7c, 0x7e, 0x7f, 0x81, + 0x7f, 0x7e, 0x7d, 0x7d, 0x7d, 0x7f, 0x80, 0x82, 0x81, 0x81, 0x7f, + 0x80, 0x81, 0x81, 0x82, 0x81, 0x86, 0x87, 0x8b, 0x84, 0x7f, 0x77, + 0x76, 0x78, 0x7d, 0x84, 0x84, 0x82, 0x7a, 0x77, 0x74, 0x77, 0x79, + 0x79, 0x78, 0x76, 0x76, 0x76, 0x79, 0x78, 0x76, 0x72, 0x72, 0x7d, + 0x8f, 0xa4, 0xab, 0xa6, 0x91, 0x7c, 0x6f, 0x70, 0x7c, 0x89, 0x92, + 0x8f, 0x88, 0x7f, 0x7d, 0x7f, 0x83, 0x81, 0x7c, 0x75, 0x72, 0x74, + 0x7b, 0x83, 0x87, 0x86, 0x80, 0x79, 0x75, 0x75, 0x78, 0x7d, 0x7f, + 0x80, 0x7e, 0x7e, 0x7f, 0x80, 0x82, 0x81, 0x80, 0x7c, 0x7f, 0x82, + 0x88, 0x89, 0x86, 0x80, 0x79, 0x78, 0x79, 0x80, 0x83, 0x85, 0x80, + 0x7b, 0x76, 0x76, 0x77, 0x79, 0x7a, 0x78, 0x76, 0x73, 0x73, 0x76, + 0x77, 0x78, 0x74, 0x76, 0x80, 0x93, 0xa7, 0xaf, 0xaa, 0x94, 0x7e, + 0x6d, 0x6e, 0x78, 0x88, 0x93, 0x93, 0x8c, 0x82, 0x7e, 0x7d, 0x80, + 0x81, 0x7e, 0x79, 0x72, 0x72, 0x75, 0x7e, 0x85, 0x88, 0x84, 0x7d, + 0x77, 0x75, 0x76, 0x7a, 0x7d, 0x80, 0x80, 0x7f, 0x7e, 0x7d, 0x80, + 0x81, 0x88, 0x89, 0x8c, 0x85, 0x7f, 0x76, 0x72, 0x76, 0x7b, 0x85, + 0x86, 0x87, 0x7c, 0x77, 0x71, 0x71, 0x73, 0x73, 0x76, 0x73, 0x76, + 0x72, 0x72, 0x6f, 0x75, 0x84, 0x98, 0xad, 0xb2, 0xac, 0x94, 0x7f, + 0x6d, 0x6d, 0x7a, 0x88, 0x94, 0x94, 0x8f, 0x84, 0x80, 0x7e, 0x81, + 0x82, 0x7f, 0x79, 0x72, 0x70, 0x74, 0x7d, 0x85, 0x89, 0x86, 0x80, + 0x77, 0x73, 0x74, 0x78, 0x7e, 0x81, 0x84, 0x84, 0x86, 0x85, 0x84, + 0x80, 0x7c, 0x78, 0x77, 0x7a, 0x7d, 0x81, 0x82, 0x81, 0x7d, 0x7a, + 0x77, 0x75, 0x74, 0x72, 0x71, 0x72, 0x72, 0x76, 0x75, 0x74, 0x70, + 0x77, 0x85, 0x9d, 0xb0, 0xb7, 0xaf, 0x96, 0x7f, 0x6c, 0x6d, 0x75, + 0x86, 0x91, 0x96, 0x92, 0x89, 0x84, 0x80, 0x80, 0x7f, 0x7d, 0x78, + 0x74, 0x70, 0x73, 0x78, 0x80, 0x86, 0x87, 0x85, 0x7f, 0x7b, 0x78, + 0x7b, 0x7d, 0x81, 0x82, 0x80, 0x7d, 0x7a, 0x7b, 0x7c, 0x7f, 0x7f, + 0x7e, 0x7b, 0x78, 0x74, 0x72, 0x72, 0x71, 0x73, 0x74, 0x76, 0x76, + 0x73, 0x70, 0x6f, 0x7a, 0x8d, 0xa8, 0xb9, 0xbe, 0xae, 0x94, 0x7a, + 0x69, 0x6b, 0x76, 0x88, 0x93, 0x96, 0x8f, 0x87, 0x7f, 0x7c, 0x7d, + 0x7e, 0x7e, 0x7b, 0x76, 0x72, 0x73, 0x78, 0x80, 0x89, 0x8f, 0x8f, + 0x88, 0x7d, 0x72, 0x6c, 0x6d, 0x74, 0x7e, 0x84, 0x86, 0x80, 0x79, + 0x72, 0x6e, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x6d, 0x6c, 0x6c, 0x78, + 0x8c, 0xa9, 0xbe, 0xc6, 0xb9, 0x9d, 0x81, 0x6b, 0x69, 0x71, 0x83, + 0x90, 0x98, 0x95, 0x8f, 0x87, 0x82, 0x7f, 0x7e, 0x7c, 0x79, 0x75, + 0x73, 0x77, 0x7e, 0x88, 0x8c, 0x8c, 0x84, 0x79, 0x6f, 0x6b, 0x6d, + 0x72, 0x78, 0x79, 0x77, 0x71, 0x6d, 0x6a, 0x6c, 0x6e, 0x6f, 0x6b, + 0x67, 0x6b, 0x7d, 0x9c, 0xbb, 0xcd, 0xc8, 0xb1, 0x8f, 0x74, 0x68, + 0x6d, 0x7b, 0x89, 0x93, 0x93, 0x8f, 0x8b, 0x89, 0x88, 0x87, 0x83, + 0x7d, 0x77, 0x72, 0x73, 0x79, 0x82, 0x88, 0x89, 0x84, 0x7c, 0x75, + 0x70, 0x71, 0x72, 0x74, 0x73, 0x71, 0x6d, 0x6a, 0x6a, 0x6b, 0x6c, + 0x69, 0x66, 0x69, 0x77, 0x91, 0xaf, 0xc6, 0xca, 0xb9, 0x9c, 0x7e, + 0x6e, 0x6d, 0x79, 0x85, 0x8e, 0x90, 0x8d, 0x8a, 0x8a, 0x8d, 0x8e, + 0x8a, 0x82, 0x79, 0x71, 0x6f, 0x70, 0x7a, 0x82, 0x8c, 0x8c, 0x89, + 0x7d, 0x72, 0x6c, 0x68, 0x6d, 0x6e, 0x74, 0x71, 0x70, 0x69, 0x67, + 0x65, 0x64, 0x63, 0x66, 0x73, 0x8a, 0xa9, 0xc0, 0xca, 0xbe, 0xa7, + 0x89, 0x76, 0x6e, 0x75, 0x7f, 0x8a, 0x8d, 0x8c, 0x89, 0x89, 0x8e, + 0x91, 0x91, 0x8a, 0x7f, 0x73, 0x6d, 0x6d, 0x77, 0x80, 0x8a, 0x89, + 0x87, 0x7b, 0x74, 0x6e, 0x6f, 0x70, 0x71, 0x71, 0x6c, 0x6a, 0x64, + 0x65, 0x61, 0x63, 0x60, 0x69, 0x78, 0x96, 0xb3, 0xc9, 0xcc, 0xba, + 0x9f, 0x80, 0x72, 0x70, 0x7c, 0x86, 0x8d, 0x8b, 0x86, 0x83, 0x85, + 0x8d, 0x93, 0x96, 0x8d, 0x82, 0x72, 0x6c, 0x6a, 0x75, 0x80, 0x8a, + 0x8c, 0x86, 0x7d, 0x71, 0x6f, 0x6c, 0x73, 0x72, 0x74, 0x6d, 0x68, + 0x63, 0x61, 0x61, 0x61, 0x62, 0x66, 0x78, 0x92, 0xb1, 0xc7, 0xcd, + 0xbe, 0xa4, 0x86, 0x74, 0x70, 0x79, 0x85, 0x8d, 0x8c, 0x87, 0x81, + 0x81, 0x87, 0x90, 0x95, 0x92, 0x87, 0x79, 0x6e, 0x6d, 0x74, 0x7f, + 0x88, 0x88, 0x82, 0x77, 0x6f, 0x6d, 0x72, 0x78, 0x7b, 0x78, 0x6f, + 0x65, 0x5f, 0x5d, 0x5f, 0x61, 0x61, 0x65, 0x71, 0x8b, 0xa8, 0xc3, + 0xce, 0xc5, 0xad, 0x8e, 0x79, 0x70, 0x77, 0x82, 0x8d, 0x8f, 0x8a, + 0x82, 0x7e, 0x82, 0x8a, 0x92, 0x93, 0x8c, 0x80, 0x74, 0x6f, 0x73, + 0x7d, 0x87, 0x8b, 0x85, 0x79, 0x6d, 0x67, 0x6a, 0x73, 0x7a, 0x7b, + 0x73, 0x69, 0x5f, 0x5b, 0x5b, 0x5e, 0x61, 0x65, 0x72, 0x85, 0xa4, + 0xbb, 0xcc, 0xc7, 0xb6, 0x9b, 0x84, 0x78, 0x77, 0x80, 0x88, 0x8e, + 0x8c, 0x87, 0x81, 0x82, 0x85, 0x8b, 0x8c, 0x8a, 0x83, 0x7a, 0x73, + 0x70, 0x77, 0x82, 0x8e, 0x91, 0x87, 0x76, 0x63, 0x5e, 0x61, 0x71, + 0x7a, 0x7f, 0x76, 0x69, 0x5d, 0x56, 0x5a, 0x5d, 0x66, 0x6b, 0x79, + 0x87, 0xa0, 0xb5, 0xc4, 0xc4, 0xb7, 0xa2, 0x8a, 0x7e, 0x79, 0x81, + 0x87, 0x8e, 0x8d, 0x8a, 0x85, 0x82, 0x84, 0x86, 0x88, 0x86, 0x82, + 0x7b, 0x76, 0x73, 0x78, 0x81, 0x8c, 0x90, 0x87, 0x78, 0x65, 0x5e, + 0x5d, 0x6a, 0x73, 0x79, 0x73, 0x69, 0x5e, 0x58, 0x5b, 0x60, 0x6a, + 0x70, 0x7c, 0x88, 0x9d, 0xae, 0xbc, 0xbe, 0xb5, 0xa4, 0x91, 0x86, + 0x81, 0x85, 0x89, 0x8e, 0x8d, 0x8a, 0x87, 0x85, 0x84, 0x85, 0x85, + 0x83, 0x80, 0x7a, 0x78, 0x75, 0x79, 0x80, 0x88, 0x8c, 0x86, 0x7b, + 0x6c, 0x64, 0x61, 0x67, 0x6e, 0x73, 0x6e, 0x66, 0x5d, 0x5a, 0x5d, + 0x64, 0x6d, 0x74, 0x79, 0x83, 0x91, 0xa4, 0xb3, 0xbb, 0xb8, 0xab, + 0x9a, 0x8b, 0x85, 0x85, 0x8a, 0x8c, 0x8e, 0x8a, 0x88, 0x85, 0x85, + 0x85, 0x85, 0x84, 0x80, 0x7d, 0x78, 0x77, 0x75, 0x7c, 0x81, 0x88, + 0x87, 0x82, 0x76, 0x6a, 0x64, 0x63, 0x69, 0x6b, 0x6e, 0x66, 0x61, + 0x5b, 0x5d, 0x62, 0x6c, 0x75, 0x7b, 0x83, 0x8c, 0x9a, 0xa8, 0xb2, + 0xb4, 0xad, 0xa0, 0x92, 0x8a, 0x87, 0x89, 0x8d, 0x8d, 0x8c, 0x88, + 0x85, 0x84, 0x85, 0x86, 0x85, 0x82, 0x7e, 0x79, 0x77, 0x76, 0x79, + 0x7d, 0x81, 0x83, 0x83, 0x7e, 0x77, 0x6f, 0x6a, 0x68, 0x6a, 0x6b, + 0x6a, 0x65, 0x60, 0x5d, 0x60, 0x65, 0x6d, 0x74, 0x7b, 0x7e, 0x86, + 0x90, 0x9d, 0xaa, 0xaf, 0xae, 0xa2, 0x98, 0x8c, 0x89, 0x89, 0x8d, + 0x8e, 0x8d, 0x88, 0x84, 0x83, 0x84, 0x86, 0x87, 0x86, 0x80, 0x7d, + 0x78, 0x78, 0x78, 0x7b, 0x7c, 0x7d, 0x7c, 0x7b, 0x7a, 0x78, 0x76, + 0x73, 0x71, 0x6d, 0x6c, 0x6a, 0x69, 0x68, 0x66, 0x66, 0x67, 0x6a, + 0x6e, 0x73, 0x7a, 0x81, 0x8a, 0x93, 0x9e, 0xa5, 0xa7, 0xa4, 0x9d, + 0x96, 0x8e, 0x8c, 0x8a, 0x8c, 0x8a, 0x88, 0x85, 0x83, 0x82, 0x83, + 0x85, 0x85, 0x85, 0x82, 0x7f, 0x7b, 0x7a, 0x78, 0x78, 0x78, 0x77, + 0x77, 0x77, 0x77, 0x78, 0x77, 0x77, 0x76, 0x75, 0x74, 0x73, 0x72, + 0x72, 0x72, 0x71, 0x72, 0x72, 0x73, 0x74, 0x76, 0x78, 0x7b, 0x7d, + 0x80, 0x82, 0x88, 0x8f, 0x97, 0x9e, 0xa0, 0x9f, 0x99, 0x93, 0x8d, + 0x8b, 0x8a, 0x8a, 0x89, 0x86, 0x82, 0x7e, 0x7d, 0x7e, 0x80, 0x81, + 0x81, 0x7f, 0x7c, 0x79, 0x78, 0x77, 0x77, 0x77, 0x76, 0x75, 0x74, + 0x74, 0x75, 0x76, 0x76, 0x76, 0x75, 0x74, 0x74, 0x74, 0x74, 0x75, + 0x76, 0x77, 0x78, 0x7b, 0x7e, 0x80, 0x82, 0x84, 0x86, 0x8b, 0x90, + 0x95, 0x97, 0x97, 0x93, 0x8e, 0x8a, 0x88, 0x87, 0x87, 0x88, 0x86, + 0x84, 0x80, 0x7e, 0x7c, 0x7d, 0x7d, 0x7e, 0x7e, 0x7d, 0x7b, 0x79, + 0x79, 0x78, 0x79, 0x78, 0x78, 0x77, 0x76, 0x76, 0x76, 0x77, 0x78, + 0x79, 0x79, 0x79, 0x78, 0x78, 0x79, 0x7a, 0x7b, 0x7d, 0x7f, 0x80, + 0x81, 0x82, 0x82, 0x83, 0x85, 0x87, 0x89, 0x8c, 0x8d, 0x8d, 0x8d, + 0x8c, 0x8a, 0x89, 0x88, 0x86, 0x85, 0x84, 0x83, 0x81, 0x80, 0x7f, + 0x7e, 0x7c, 0x7b, 0x7b, 0x7a, 0x79, 0x78, 0x76, 0x75, 0x73, 0x71, + 0x70, 0x6f, 0x70, 0x72, 0x74, 0x76, 0x78, 0x7a, 0x7c, 0x7f, 0x81, + 0x84, 0x88, 0x8c, 0x8f, 0x91, 0x91, 0x8f, 0x8c, 0x89, 0x87, 0x85, + 0x85, 0x84, 0x83, 0x81, 0x7f, 0x7d, 0x7c, 0x7d, 0x7d, 0x7e, 0x7e, + 0x7e, 0x7d, 0x7c, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, + 0x7b, 0x7c, 0x7d, 0x7d, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x81, 0x81, 0x81, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x81, 0x81, 0x81, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, + 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, + }, + }, +} + +var beepSound = []byte{ + 0x80, 0x80, 0x81, 0x81, 0x7f, 0x7e, 0x7e, 0x80, 0x7e, 0x79, 0x76, + 0x78, 0x81, 0x8c, 0x8f, 0x88, 0x7d, 0x78, 0x7b, 0x80, 0x7d, 0x73, + 0x6c, 0x73, 0x88, 0x9b, 0x9d, 0x8c, 0x76, 0x6d, 0x74, 0x7e, 0x7c, + 0x70, 0x68, 0x75, 0x8f, 0xa4, 0xa2, 0x89, 0x6f, 0x66, 0x70, 0x7d, + 0x7e, 0x74, 0x6e, 0x7b, 0x93, 0xa5, 0x9f, 0x84, 0x6a, 0x62, 0x6e, + 0x7e, 0x81, 0x79, 0x73, 0x7e, 0x95, 0xa4, 0x9a, 0x7e, 0x64, 0x5f, + 0x6e, 0x81, 0x86, 0x7e, 0x78, 0x82, 0x96, 0xa1, 0x95, 0x78, 0x5f, + 0x5d, 0x70, 0x84, 0x8a, 0x83, 0x7c, 0x84, 0x94, 0x9d, 0x8f, 0x72, + 0x5c, 0x5c, 0x72, 0x89, 0x90, 0x87, 0x7f, 0x84, 0x92, 0x98, 0x89, + 0x6d, 0x59, 0x5e, 0x77, 0x8f, 0x95, 0x8a, 0x80, 0x82, 0x8e, 0x93, + 0x84, 0x6a, 0x58, 0x61, 0x7c, 0x94, 0x9a, 0x8d, 0x80, 0x80, 0x8a, + 0x8d, 0x7f, 0x67, 0x5a, 0x65, 0x82, 0x9a, 0x9d, 0x8e, 0x7d, 0x7c, + 0x84, 0x88, 0x7b, 0x66, 0x5c, 0x6a, 0x88, 0x9f, 0x9f, 0x8d, 0x7b, + 0x77, 0x7f, 0x84, 0x79, 0x67, 0x60, 0x70, 0x8e, 0xa3, 0xa0, 0x8a, + 0x76, 0x72, 0x7b, 0x81, 0x78, 0x69, 0x65, 0x76, 0x93, 0xa5, 0x9f, + 0x86, 0x70, 0x6c, 0x77, 0x7f, 0x79, 0x6c, 0x6a, 0x7c, 0x97, 0xa7, + 0x9d, 0x81, 0x6b, 0x68, 0x74, 0x7f, 0x7c, 0x71, 0x70, 0x81, 0x9a, + 0xa6, 0x99, 0x7c, 0x65, 0x64, 0x73, 0x81, 0x80, 0x76, 0x75, 0x84, + 0x9b, 0xa4, 0x94, 0x76, 0x60, 0x61, 0x74, 0x84, 0x84, 0x7b, 0x79, + 0x87, 0x9a, 0xa0, 0x8e, 0x70, 0x5c, 0x61, 0x76, 0x88, 0x89, 0x80, + 0x7d, 0x88, 0x98, 0x9c, 0x88, 0x6a, 0x59, 0x61, 0x79, 0x8d, 0x8e, + 0x84, 0x7e, 0x88, 0x95, 0x96, 0x82, 0x66, 0x58, 0x63, 0x7e, 0x93, + 0x93, 0x87, 0x7f, 0x86, 0x91, 0x91, 0x7d, 0x63, 0x58, 0x67, 0x84, + 0x98, 0x97, 0x89, 0x7e, 0x82, 0x8c, 0x8b, 0x78, 0x61, 0x5a, 0x6c, + 0x8a, 0x9e, 0x9a, 0x88, 0x7c, 0x7e, 0x87, 0x86, 0x76, 0x61, 0x5d, + 0x71, 0x8f, 0xa2, 0x9c, 0x87, 0x78, 0x79, 0x82, 0x82, 0x74, 0x63, + 0x62, 0x77, 0x95, 0xa5, 0x9b, 0x84, 0x73, 0x73, 0x7d, 0x80, 0x74, + 0x66, 0x67, 0x7d, 0x9a, 0xa7, 0x9a, 0x80, 0x6d, 0x6e, 0x7b, 0x7f, + 0x76, 0x6a, 0x6c, 0x83, 0x9d, 0xa7, 0x96, 0x7a, 0x68, 0x6b, 0x78, + 0x80, 0x79, 0x6f, 0x72, 0x88, 0x9f, 0xa5, 0x92, 0x74, 0x62, 0x67, + 0x78, 0x82, 0x7d, 0x74, 0x77, 0x8a, 0x9f, 0xa2, 0x8c, 0x6e, 0x5e, + 0x66, 0x79, 0x86, 0x82, 0x79, 0x7c, 0x8d, 0x9e, 0x9e, 0x86, 0x68, + 0x5b, 0x66, 0x7c, 0x8a, 0x87, 0x7e, 0x7e, 0x8d, 0x9c, 0x98, 0x80, + 0x63, 0x59, 0x67, 0x80, 0x8f, 0x8c, 0x81, 0x80, 0x8c, 0x98, 0x93, + 0x7b, 0x60, 0x58, 0x6a, 0x85, 0x94, 0x91, 0x84, 0x80, 0x89, 0x93, + 0x8d, 0x76, 0x5d, 0x5a, 0x6e, 0x8b, 0x9a, 0x94, 0x84, 0x7e, 0x85, + 0x8e, 0x88, 0x72, 0x5d, 0x5c, 0x73, 0x91, 0x9f, 0x96, 0x84, 0x7b, + 0x80, 0x88, 0x83, 0x70, 0x5e, 0x61, 0x79, 0x97, 0xa2, 0x97, 0x81, + 0x77, 0x7b, 0x84, 0x80, 0x6f, 0x60, 0x66, 0x80, 0x9c, 0xa4, 0x95, + 0x7d, 0x71, 0x76, 0x80, 0x7e, 0x70, 0x64, 0x6b, 0x86, 0xa0, 0xa5, + 0x93, 0x79, 0x6c, 0x72, 0x7d, 0x7e, 0x72, 0x68, 0x71, 0x8a, 0xa2, + 0xa4, 0x8f, 0x73, 0x67, 0x6e, 0x7c, 0x7f, 0x76, 0x6e, 0x77, 0x8e, + 0xa3, 0xa2, 0x89, 0x6d, 0x62, 0x6c, 0x7c, 0x82, 0x7b, 0x73, 0x7b, + 0x91, 0xa3, 0x9e, 0x84, 0x67, 0x5e, 0x6b, 0x7e, 0x86, 0x80, 0x78, + 0x7f, 0x92, 0xa0, 0x99, 0x7d, 0x62, 0x5c, 0x6b, 0x81, 0x8b, 0x84, + 0x7c, 0x81, 0x92, 0x9d, 0x93, 0x78, 0x5e, 0x5a, 0x6e, 0x86, 0x90, + 0x89, 0x80, 0x82, 0x90, 0x98, 0x8e, 0x72, 0x5b, 0x5b, 0x72, 0x8c, + 0x95, 0x8d, 0x81, 0x81, 0x8d, 0x93, 0x88, 0x6e, 0x5a, 0x5d, 0x76, + 0x91, 0x9a, 0x8f, 0x81, 0x7e, 0x88, 0x8e, 0x83, 0x6b, 0x5a, 0x61, + 0x7c, 0x97, 0x9e, 0x91, 0x80, 0x7b, 0x83, 0x89, 0x7e, 0x6a, 0x5c, + 0x66, 0x82, 0x9b, 0x9f, 0x8f, 0x7d, 0x78, 0x7e, 0x83, 0x7d, 0x70, + 0x6a, 0x72, 0x85, 0x93, 0x93, 0x88, 0x7c, 0x79, 0x7d, 0x80, 0x7d, + 0x78, 0x77, 0x7b, 0x83, 0x87, 0x86, 0x81, 0x7e, 0x7d, 0x7e, 0x7f, + 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, + 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, + 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, + 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x80, + 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7f, + 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7f, + 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, + 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x80, + 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, + 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, + 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, + 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7f, + 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, + 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, + 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x80, + 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, + 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, + 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, + 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, + 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, + 0x80, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, + 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, + 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x80, + 0x7f, 0x80, 0x7f, 0x7f, 0x80, +} diff --git a/contrib/backends/nntpchand/src/vendor/github.com/dchest/captcha/store.go b/contrib/backends/nntpchand/src/vendor/github.com/dchest/captcha/store.go new file mode 100644 index 0000000..5dd1521 --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/dchest/captcha/store.go @@ -0,0 +1,117 @@ +// Copyright 2011 Dmitry Chestnykh. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package captcha + +import ( + "container/list" + "sync" + "time" +) + +// An object implementing Store interface can be registered with SetCustomStore +// function to handle storage and retrieval of captcha ids and solutions for +// them, replacing the default memory store. +// +// It is the responsibility of an object to delete expired and used captchas +// when necessary (for example, the default memory store collects them in Set +// method after the certain amount of captchas has been stored.) +type Store interface { + // Set sets the digits for the captcha id. + Set(id string, digits []byte) + + // Get returns stored digits for the captcha id. Clear indicates + // whether the captcha must be deleted from the store. + Get(id string, clear bool) (digits []byte) +} + +// expValue stores timestamp and id of captchas. It is used in the list inside +// memoryStore for indexing generated captchas by timestamp to enable garbage +// collection of expired captchas. +type idByTimeValue struct { + timestamp time.Time + id string +} + +// memoryStore is an internal store for captcha ids and their values. +type memoryStore struct { + sync.RWMutex + digitsById map[string][]byte + idByTime *list.List + // Number of items stored since last collection. + numStored int + // Number of saved items that triggers collection. + collectNum int + // Expiration time of captchas. + expiration time.Duration +} + +// NewMemoryStore returns a new standard memory store for captchas with the +// given collection threshold and expiration time (duration). The returned +// store must be registered with SetCustomStore to replace the default one. +func NewMemoryStore(collectNum int, expiration time.Duration) Store { + s := new(memoryStore) + s.digitsById = make(map[string][]byte) + s.idByTime = list.New() + s.collectNum = collectNum + s.expiration = expiration + return s +} + +func (s *memoryStore) Set(id string, digits []byte) { + s.Lock() + s.digitsById[id] = digits + s.idByTime.PushBack(idByTimeValue{time.Now(), id}) + s.numStored++ + if s.numStored <= s.collectNum { + s.Unlock() + return + } + s.Unlock() + go s.collect() +} + +func (s *memoryStore) Get(id string, clear bool) (digits []byte) { + if !clear { + // When we don't need to clear captcha, acquire read lock. + s.RLock() + defer s.RUnlock() + } else { + s.Lock() + defer s.Unlock() + } + digits, ok := s.digitsById[id] + if !ok { + return + } + if clear { + delete(s.digitsById, id) + // XXX(dchest) Index (s.idByTime) will be cleaned when + // collecting expired captchas. Can't clean it here, because + // we don't store reference to expValue in the map. + // Maybe store it? + } + return +} + +func (s *memoryStore) collect() { + now := time.Now() + s.Lock() + defer s.Unlock() + s.numStored = 0 + for e := s.idByTime.Front(); e != nil; { + ev, ok := e.Value.(idByTimeValue) + if !ok { + return + } + if ev.timestamp.Add(s.expiration).Before(now) { + delete(s.digitsById, ev.id) + next := e.Next() + s.idByTime.Remove(e) + e = next + } else { + return + } + } +} diff --git a/contrib/backends/nntpchand/src/vendor/github.com/dchest/captcha/store_test.go b/contrib/backends/nntpchand/src/vendor/github.com/dchest/captcha/store_test.go new file mode 100644 index 0000000..d9ecc7b --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/dchest/captcha/store_test.go @@ -0,0 +1,79 @@ +// Copyright 2011 Dmitry Chestnykh. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package captcha + +import ( + "bytes" + "testing" +) + +func TestSetGet(t *testing.T) { + s := NewMemoryStore(CollectNum, Expiration) + id := "captcha id" + d := RandomDigits(10) + s.Set(id, d) + d2 := s.Get(id, false) + if d2 == nil || !bytes.Equal(d, d2) { + t.Errorf("saved %v, getDigits returned got %v", d, d2) + } +} + +func TestGetClear(t *testing.T) { + s := NewMemoryStore(CollectNum, Expiration) + id := "captcha id" + d := RandomDigits(10) + s.Set(id, d) + d2 := s.Get(id, true) + if d2 == nil || !bytes.Equal(d, d2) { + t.Errorf("saved %v, getDigitsClear returned got %v", d, d2) + } + d2 = s.Get(id, false) + if d2 != nil { + t.Errorf("getDigitClear didn't clear (%q=%v)", id, d2) + } +} + +func TestCollect(t *testing.T) { + //TODO(dchest): can't test automatic collection when saving, because + //it's currently launched in a different goroutine. + s := NewMemoryStore(10, -1) + // create 10 ids + ids := make([]string, 10) + d := RandomDigits(10) + for i := range ids { + ids[i] = randomId() + s.Set(ids[i], d) + } + s.(*memoryStore).collect() + // Must be already collected + nc := 0 + for i := range ids { + d2 := s.Get(ids[i], false) + if d2 != nil { + t.Errorf("%d: not collected", i) + nc++ + } + } + if nc > 0 { + t.Errorf("= not collected %d out of %d captchas", nc, len(ids)) + } +} + +func BenchmarkSetCollect(b *testing.B) { + b.StopTimer() + d := RandomDigits(10) + s := NewMemoryStore(9999, -1) + ids := make([]string, 1000) + for i := range ids { + ids[i] = randomId() + } + b.StartTimer() + for i := 0; i < b.N; i++ { + for j := 0; j < 1000; j++ { + s.Set(ids[j], d) + } + s.(*memoryStore).collect() + } +} diff --git a/contrib/backends/nntpchand/src/vendor/github.com/gorilla/context/.travis.yml b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/context/.travis.yml new file mode 100644 index 0000000..6f440f1 --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/context/.travis.yml @@ -0,0 +1,19 @@ +language: go +sudo: false + +matrix: + include: + - go: 1.3 + - go: 1.4 + - go: 1.5 + - go: 1.6 + - go: 1.7 + - go: tip + allow_failures: + - go: tip + +script: + - go get -t -v ./... + - diff -u <(echo -n) <(gofmt -d .) + - go vet $(go list ./... | grep -v /vendor/) + - go test -v -race ./... diff --git a/contrib/backends/nntpchand/src/vendor/github.com/gorilla/context/LICENSE b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/context/LICENSE new file mode 100644 index 0000000..0e5fb87 --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/context/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2012 Rodrigo Moraes. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/contrib/backends/nntpchand/src/vendor/github.com/gorilla/context/README.md b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/context/README.md new file mode 100644 index 0000000..08f8669 --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/context/README.md @@ -0,0 +1,10 @@ +context +======= +[![Build Status](https://travis-ci.org/gorilla/context.png?branch=master)](https://travis-ci.org/gorilla/context) + +gorilla/context is a general purpose registry for global request variables. + +> Note: gorilla/context, having been born well before `context.Context` existed, does not play well +> with the shallow copying of the request that [`http.Request.WithContext`](https://golang.org/pkg/net/http/#Request.WithContext) (added to net/http Go 1.7 onwards) performs. You should either use *just* gorilla/context, or moving forward, the new `http.Request.Context()`. + +Read the full documentation here: http://www.gorillatoolkit.org/pkg/context diff --git a/contrib/backends/nntpchand/src/vendor/github.com/gorilla/context/context.go b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/context/context.go new file mode 100644 index 0000000..81cb128 --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/context/context.go @@ -0,0 +1,143 @@ +// Copyright 2012 The Gorilla 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 context + +import ( + "net/http" + "sync" + "time" +) + +var ( + mutex sync.RWMutex + data = make(map[*http.Request]map[interface{}]interface{}) + datat = make(map[*http.Request]int64) +) + +// Set stores a value for a given key in a given request. +func Set(r *http.Request, key, val interface{}) { + mutex.Lock() + if data[r] == nil { + data[r] = make(map[interface{}]interface{}) + datat[r] = time.Now().Unix() + } + data[r][key] = val + mutex.Unlock() +} + +// Get returns a value stored for a given key in a given request. +func Get(r *http.Request, key interface{}) interface{} { + mutex.RLock() + if ctx := data[r]; ctx != nil { + value := ctx[key] + mutex.RUnlock() + return value + } + mutex.RUnlock() + return nil +} + +// GetOk returns stored value and presence state like multi-value return of map access. +func GetOk(r *http.Request, key interface{}) (interface{}, bool) { + mutex.RLock() + if _, ok := data[r]; ok { + value, ok := data[r][key] + mutex.RUnlock() + return value, ok + } + mutex.RUnlock() + return nil, false +} + +// GetAll returns all stored values for the request as a map. Nil is returned for invalid requests. +func GetAll(r *http.Request) map[interface{}]interface{} { + mutex.RLock() + if context, ok := data[r]; ok { + result := make(map[interface{}]interface{}, len(context)) + for k, v := range context { + result[k] = v + } + mutex.RUnlock() + return result + } + mutex.RUnlock() + return nil +} + +// GetAllOk returns all stored values for the request as a map and a boolean value that indicates if +// the request was registered. +func GetAllOk(r *http.Request) (map[interface{}]interface{}, bool) { + mutex.RLock() + context, ok := data[r] + result := make(map[interface{}]interface{}, len(context)) + for k, v := range context { + result[k] = v + } + mutex.RUnlock() + return result, ok +} + +// Delete removes a value stored for a given key in a given request. +func Delete(r *http.Request, key interface{}) { + mutex.Lock() + if data[r] != nil { + delete(data[r], key) + } + mutex.Unlock() +} + +// Clear removes all values stored for a given request. +// +// This is usually called by a handler wrapper to clean up request +// variables at the end of a request lifetime. See ClearHandler(). +func Clear(r *http.Request) { + mutex.Lock() + clear(r) + mutex.Unlock() +} + +// clear is Clear without the lock. +func clear(r *http.Request) { + delete(data, r) + delete(datat, r) +} + +// Purge removes request data stored for longer than maxAge, in seconds. +// It returns the amount of requests removed. +// +// If maxAge <= 0, all request data is removed. +// +// This is only used for sanity check: in case context cleaning was not +// properly set some request data can be kept forever, consuming an increasing +// amount of memory. In case this is detected, Purge() must be called +// periodically until the problem is fixed. +func Purge(maxAge int) int { + mutex.Lock() + count := 0 + if maxAge <= 0 { + count = len(data) + data = make(map[*http.Request]map[interface{}]interface{}) + datat = make(map[*http.Request]int64) + } else { + min := time.Now().Unix() - int64(maxAge) + for r := range data { + if datat[r] < min { + clear(r) + count++ + } + } + } + mutex.Unlock() + return count +} + +// ClearHandler wraps an http.Handler and clears request values at the end +// of a request lifetime. +func ClearHandler(h http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + defer Clear(r) + h.ServeHTTP(w, r) + }) +} diff --git a/contrib/backends/nntpchand/src/vendor/github.com/gorilla/context/context_test.go b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/context/context_test.go new file mode 100644 index 0000000..d70e91a --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/context/context_test.go @@ -0,0 +1,161 @@ +// Copyright 2012 The Gorilla 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 context + +import ( + "net/http" + "testing" +) + +type keyType int + +const ( + key1 keyType = iota + key2 +) + +func TestContext(t *testing.T) { + assertEqual := func(val interface{}, exp interface{}) { + if val != exp { + t.Errorf("Expected %v, got %v.", exp, val) + } + } + + r, _ := http.NewRequest("GET", "http://localhost:8080/", nil) + emptyR, _ := http.NewRequest("GET", "http://localhost:8080/", nil) + + // Get() + assertEqual(Get(r, key1), nil) + + // Set() + Set(r, key1, "1") + assertEqual(Get(r, key1), "1") + assertEqual(len(data[r]), 1) + + Set(r, key2, "2") + assertEqual(Get(r, key2), "2") + assertEqual(len(data[r]), 2) + + //GetOk + value, ok := GetOk(r, key1) + assertEqual(value, "1") + assertEqual(ok, true) + + value, ok = GetOk(r, "not exists") + assertEqual(value, nil) + assertEqual(ok, false) + + Set(r, "nil value", nil) + value, ok = GetOk(r, "nil value") + assertEqual(value, nil) + assertEqual(ok, true) + + // GetAll() + values := GetAll(r) + assertEqual(len(values), 3) + + // GetAll() for empty request + values = GetAll(emptyR) + if values != nil { + t.Error("GetAll didn't return nil value for invalid request") + } + + // GetAllOk() + values, ok = GetAllOk(r) + assertEqual(len(values), 3) + assertEqual(ok, true) + + // GetAllOk() for empty request + values, ok = GetAllOk(emptyR) + assertEqual(len(values), 0) + assertEqual(ok, false) + + // Delete() + Delete(r, key1) + assertEqual(Get(r, key1), nil) + assertEqual(len(data[r]), 2) + + Delete(r, key2) + assertEqual(Get(r, key2), nil) + assertEqual(len(data[r]), 1) + + // Clear() + Clear(r) + assertEqual(len(data), 0) +} + +func parallelReader(r *http.Request, key string, iterations int, wait, done chan struct{}) { + <-wait + for i := 0; i < iterations; i++ { + Get(r, key) + } + done <- struct{}{} + +} + +func parallelWriter(r *http.Request, key, value string, iterations int, wait, done chan struct{}) { + <-wait + for i := 0; i < iterations; i++ { + Set(r, key, value) + } + done <- struct{}{} + +} + +func benchmarkMutex(b *testing.B, numReaders, numWriters, iterations int) { + + b.StopTimer() + r, _ := http.NewRequest("GET", "http://localhost:8080/", nil) + done := make(chan struct{}) + b.StartTimer() + + for i := 0; i < b.N; i++ { + wait := make(chan struct{}) + + for i := 0; i < numReaders; i++ { + go parallelReader(r, "test", iterations, wait, done) + } + + for i := 0; i < numWriters; i++ { + go parallelWriter(r, "test", "123", iterations, wait, done) + } + + close(wait) + + for i := 0; i < numReaders+numWriters; i++ { + <-done + } + + } + +} + +func BenchmarkMutexSameReadWrite1(b *testing.B) { + benchmarkMutex(b, 1, 1, 32) +} +func BenchmarkMutexSameReadWrite2(b *testing.B) { + benchmarkMutex(b, 2, 2, 32) +} +func BenchmarkMutexSameReadWrite4(b *testing.B) { + benchmarkMutex(b, 4, 4, 32) +} +func BenchmarkMutex1(b *testing.B) { + benchmarkMutex(b, 2, 8, 32) +} +func BenchmarkMutex2(b *testing.B) { + benchmarkMutex(b, 16, 4, 64) +} +func BenchmarkMutex3(b *testing.B) { + benchmarkMutex(b, 1, 2, 128) +} +func BenchmarkMutex4(b *testing.B) { + benchmarkMutex(b, 128, 32, 256) +} +func BenchmarkMutex5(b *testing.B) { + benchmarkMutex(b, 1024, 2048, 64) +} +func BenchmarkMutex6(b *testing.B) { + benchmarkMutex(b, 2048, 1024, 512) +} diff --git a/contrib/backends/nntpchand/src/vendor/github.com/gorilla/context/doc.go b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/context/doc.go new file mode 100644 index 0000000..448d1bf --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/context/doc.go @@ -0,0 +1,88 @@ +// Copyright 2012 The Gorilla 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 context stores values shared during a request lifetime. + +Note: gorilla/context, having been born well before `context.Context` existed, +does not play well > with the shallow copying of the request that +[`http.Request.WithContext`](https://golang.org/pkg/net/http/#Request.WithContext) +(added to net/http Go 1.7 onwards) performs. You should either use *just* +gorilla/context, or moving forward, the new `http.Request.Context()`. + +For example, a router can set variables extracted from the URL and later +application handlers can access those values, or it can be used to store +sessions values to be saved at the end of a request. There are several +others common uses. + +The idea was posted by Brad Fitzpatrick to the go-nuts mailing list: + + http://groups.google.com/group/golang-nuts/msg/e2d679d303aa5d53 + +Here's the basic usage: first define the keys that you will need. The key +type is interface{} so a key can be of any type that supports equality. +Here we define a key using a custom int type to avoid name collisions: + + package foo + + import ( + "github.com/gorilla/context" + ) + + type key int + + const MyKey key = 0 + +Then set a variable. Variables are bound to an http.Request object, so you +need a request instance to set a value: + + context.Set(r, MyKey, "bar") + +The application can later access the variable using the same key you provided: + + func MyHandler(w http.ResponseWriter, r *http.Request) { + // val is "bar". + val := context.Get(r, foo.MyKey) + + // returns ("bar", true) + val, ok := context.GetOk(r, foo.MyKey) + // ... + } + +And that's all about the basic usage. We discuss some other ideas below. + +Any type can be stored in the context. To enforce a given type, make the key +private and wrap Get() and Set() to accept and return values of a specific +type: + + type key int + + const mykey key = 0 + + // GetMyKey returns a value for this package from the request values. + func GetMyKey(r *http.Request) SomeType { + if rv := context.Get(r, mykey); rv != nil { + return rv.(SomeType) + } + return nil + } + + // SetMyKey sets a value for this package in the request values. + func SetMyKey(r *http.Request, val SomeType) { + context.Set(r, mykey, val) + } + +Variables must be cleared at the end of a request, to remove all values +that were stored. This can be done in an http.Handler, after a request was +served. Just call Clear() passing the request: + + context.Clear(r) + +...or use ClearHandler(), which conveniently wraps an http.Handler to clear +variables at the end of a request lifetime. + +The Routers from the packages gorilla/mux and gorilla/pat call Clear() +so if you are using either of them you don't need to clear the context manually. +*/ +package context diff --git a/contrib/backends/nntpchand/src/vendor/github.com/gorilla/mux/.travis.yml b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/mux/.travis.yml new file mode 100644 index 0000000..ca377e6 --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/mux/.travis.yml @@ -0,0 +1,22 @@ +language: go +sudo: false + +matrix: + include: + - go: 1.2 + - go: 1.3 + - go: 1.4 + - go: 1.5 + - go: 1.6 + - go: 1.7 + - go: 1.8 + - go: tip + +install: + - # Skip + +script: + - go get -t -v ./... + - diff -u <(echo -n) <(gofmt -d .) + - go tool vet . + - go test -v -race ./... diff --git a/contrib/backends/nntpchand/src/vendor/github.com/gorilla/mux/LICENSE b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/mux/LICENSE new file mode 100644 index 0000000..0e5fb87 --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/mux/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2012 Rodrigo Moraes. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/contrib/backends/nntpchand/src/vendor/github.com/gorilla/mux/README.md b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/mux/README.md new file mode 100644 index 0000000..cdab878 --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/mux/README.md @@ -0,0 +1,340 @@ +gorilla/mux +=== +[![GoDoc](https://godoc.org/github.com/gorilla/mux?status.svg)](https://godoc.org/github.com/gorilla/mux) +[![Build Status](https://travis-ci.org/gorilla/mux.svg?branch=master)](https://travis-ci.org/gorilla/mux) +[![Sourcegraph](https://sourcegraph.com/github.com/gorilla/mux/-/badge.svg)](https://sourcegraph.com/github.com/gorilla/mux?badge) + +![Gorilla Logo](http://www.gorillatoolkit.org/static/images/gorilla-icon-64.png) + +http://www.gorillatoolkit.org/pkg/mux + +Package `gorilla/mux` implements a request router and dispatcher for matching incoming requests to +their respective handler. + +The name mux stands for "HTTP request multiplexer". Like the standard `http.ServeMux`, `mux.Router` matches incoming requests against a list of registered routes and calls a handler for the route that matches the URL or other conditions. The main features are: + +* It implements the `http.Handler` interface so it is compatible with the standard `http.ServeMux`. +* Requests can be matched based on URL host, path, path prefix, schemes, header and query values, HTTP methods or using custom matchers. +* URL hosts and paths can have variables with an optional regular expression. +* Registered URLs can be built, or "reversed", which helps maintaining references to resources. +* Routes can be used as subrouters: nested routes are only tested if the parent route matches. This is useful to define groups of routes that share common conditions like a host, a path prefix or other repeated attributes. As a bonus, this optimizes request matching. + +--- + +* [Install](#install) +* [Examples](#examples) +* [Matching Routes](#matching-routes) +* [Listing Routes](#listing-routes) +* [Static Files](#static-files) +* [Registered URLs](#registered-urls) +* [Full Example](#full-example) + +--- + +## Install + +With a [correctly configured](https://golang.org/doc/install#testing) Go toolchain: + +```sh +go get -u github.com/gorilla/mux +``` + +## Examples + +Let's start registering a couple of URL paths and handlers: + +```go +func main() { + r := mux.NewRouter() + r.HandleFunc("/", HomeHandler) + r.HandleFunc("/products", ProductsHandler) + r.HandleFunc("/articles", ArticlesHandler) + http.Handle("/", r) +} +``` + +Here we register three routes mapping URL paths to handlers. This is equivalent to how `http.HandleFunc()` works: if an incoming request URL matches one of the paths, the corresponding handler is called passing (`http.ResponseWriter`, `*http.Request`) as parameters. + +Paths can have variables. They are defined using the format `{name}` or `{name:pattern}`. If a regular expression pattern is not defined, the matched variable will be anything until the next slash. For example: + +```go +r := mux.NewRouter() +r.HandleFunc("/products/{key}", ProductHandler) +r.HandleFunc("/articles/{category}/", ArticlesCategoryHandler) +r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler) +``` + +The names are used to create a map of route variables which can be retrieved calling `mux.Vars()`: + +```go +func ArticlesCategoryHandler(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + w.WriteHeader(http.StatusOK) + fmt.Fprintf(w, "Category: %v\n", vars["category"]) +} +``` + +And this is all you need to know about the basic usage. More advanced options are explained below. + +### Matching Routes + +Routes can also be restricted to a domain or subdomain. Just define a host pattern to be matched. They can also have variables: + +```go +r := mux.NewRouter() +// Only matches if domain is "www.example.com". +r.Host("www.example.com") +// Matches a dynamic subdomain. +r.Host("{subdomain:[a-z]+}.domain.com") +``` + +There are several other matchers that can be added. To match path prefixes: + +```go +r.PathPrefix("/products/") +``` + +...or HTTP methods: + +```go +r.Methods("GET", "POST") +``` + +...or URL schemes: + +```go +r.Schemes("https") +``` + +...or header values: + +```go +r.Headers("X-Requested-With", "XMLHttpRequest") +``` + +...or query values: + +```go +r.Queries("key", "value") +``` + +...or to use a custom matcher function: + +```go +r.MatcherFunc(func(r *http.Request, rm *RouteMatch) bool { + return r.ProtoMajor == 0 +}) +``` + +...and finally, it is possible to combine several matchers in a single route: + +```go +r.HandleFunc("/products", ProductsHandler). + Host("www.example.com"). + Methods("GET"). + Schemes("http") +``` + +Setting the same matching conditions again and again can be boring, so we have a way to group several routes that share the same requirements. We call it "subrouting". + +For example, let's say we have several URLs that should only match when the host is `www.example.com`. Create a route for that host and get a "subrouter" from it: + +```go +r := mux.NewRouter() +s := r.Host("www.example.com").Subrouter() +``` + +Then register routes in the subrouter: + +```go +s.HandleFunc("/products/", ProductsHandler) +s.HandleFunc("/products/{key}", ProductHandler) +s.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler) +``` + +The three URL paths we registered above will only be tested if the domain is `www.example.com`, because the subrouter is tested first. This is not only convenient, but also optimizes request matching. You can create subrouters combining any attribute matchers accepted by a route. + +Subrouters can be used to create domain or path "namespaces": you define subrouters in a central place and then parts of the app can register its paths relatively to a given subrouter. + +There's one more thing about subroutes. When a subrouter has a path prefix, the inner routes use it as base for their paths: + +```go +r := mux.NewRouter() +s := r.PathPrefix("/products").Subrouter() +// "/products/" +s.HandleFunc("/", ProductsHandler) +// "/products/{key}/" +s.HandleFunc("/{key}/", ProductHandler) +// "/products/{key}/details" +s.HandleFunc("/{key}/details", ProductDetailsHandler) +``` + +### Listing Routes + +Routes on a mux can be listed using the Router.Walk method—useful for generating documentation: + +```go +package main + +import ( + "fmt" + "net/http" + + "github.com/gorilla/mux" +) + +func handler(w http.ResponseWriter, r *http.Request) { + return +} + +func main() { + r := mux.NewRouter() + r.HandleFunc("/", handler) + r.HandleFunc("/products", handler) + r.HandleFunc("/articles", handler) + r.HandleFunc("/articles/{id}", handler) + r.Walk(func(route *mux.Route, router *mux.Router, ancestors []*mux.Route) error { + t, err := route.GetPathTemplate() + if err != nil { + return err + } + fmt.Println(t) + return nil + }) + http.Handle("/", r) +} +``` + +### Static Files + +Note that the path provided to `PathPrefix()` represents a "wildcard": calling +`PathPrefix("/static/").Handler(...)` means that the handler will be passed any +request that matches "/static/*". This makes it easy to serve static files with mux: + +```go +func main() { + var dir string + + flag.StringVar(&dir, "dir", ".", "the directory to serve files from. Defaults to the current dir") + flag.Parse() + r := mux.NewRouter() + + // This will serve files under http://localhost:8000/static/ + r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir(dir)))) + + srv := &http.Server{ + Handler: r, + Addr: "127.0.0.1:8000", + // Good practice: enforce timeouts for servers you create! + WriteTimeout: 15 * time.Second, + ReadTimeout: 15 * time.Second, + } + + log.Fatal(srv.ListenAndServe()) +} +``` + +### Registered URLs + +Now let's see how to build registered URLs. + +Routes can be named. All routes that define a name can have their URLs built, or "reversed". We define a name calling `Name()` on a route. For example: + +```go +r := mux.NewRouter() +r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler). + Name("article") +``` + +To build a URL, get the route and call the `URL()` method, passing a sequence of key/value pairs for the route variables. For the previous route, we would do: + +```go +url, err := r.Get("article").URL("category", "technology", "id", "42") +``` + +...and the result will be a `url.URL` with the following path: + +``` +"/articles/technology/42" +``` + +This also works for host variables: + +```go +r := mux.NewRouter() +r.Host("{subdomain}.domain.com"). + Path("/articles/{category}/{id:[0-9]+}"). + HandlerFunc(ArticleHandler). + Name("article") + +// url.String() will be "http://news.domain.com/articles/technology/42" +url, err := r.Get("article").URL("subdomain", "news", + "category", "technology", + "id", "42") +``` + +All variables defined in the route are required, and their values must conform to the corresponding patterns. These requirements guarantee that a generated URL will always match a registered route -- the only exception is for explicitly defined "build-only" routes which never match. + +Regex support also exists for matching Headers within a route. For example, we could do: + +```go +r.HeadersRegexp("Content-Type", "application/(text|json)") +``` + +...and the route will match both requests with a Content-Type of `application/json` as well as `application/text` + +There's also a way to build only the URL host or path for a route: use the methods `URLHost()` or `URLPath()` instead. For the previous route, we would do: + +```go +// "http://news.domain.com/" +host, err := r.Get("article").URLHost("subdomain", "news") + +// "/articles/technology/42" +path, err := r.Get("article").URLPath("category", "technology", "id", "42") +``` + +And if you use subrouters, host and path defined separately can be built as well: + +```go +r := mux.NewRouter() +s := r.Host("{subdomain}.domain.com").Subrouter() +s.Path("/articles/{category}/{id:[0-9]+}"). + HandlerFunc(ArticleHandler). + Name("article") + +// "http://news.domain.com/articles/technology/42" +url, err := r.Get("article").URL("subdomain", "news", + "category", "technology", + "id", "42") +``` + +## Full Example + +Here's a complete, runnable example of a small `mux` based server: + +```go +package main + +import ( + "net/http" + "log" + "github.com/gorilla/mux" +) + +func YourHandler(w http.ResponseWriter, r *http.Request) { + w.Write([]byte("Gorilla!\n")) +} + +func main() { + r := mux.NewRouter() + // Routes consist of a path and a handler function. + r.HandleFunc("/", YourHandler) + + // Bind to a port and pass our router in + log.Fatal(http.ListenAndServe(":8000", r)) +} +``` + +## License + +BSD licensed. See the LICENSE file for details. diff --git a/contrib/backends/nntpchand/src/vendor/github.com/gorilla/mux/bench_test.go b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/mux/bench_test.go new file mode 100644 index 0000000..522156d --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/mux/bench_test.go @@ -0,0 +1,49 @@ +// Copyright 2012 The Gorilla 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 mux + +import ( + "net/http" + "net/http/httptest" + "testing" +) + +func BenchmarkMux(b *testing.B) { + router := new(Router) + handler := func(w http.ResponseWriter, r *http.Request) {} + router.HandleFunc("/v1/{v1}", handler) + + request, _ := http.NewRequest("GET", "/v1/anything", nil) + for i := 0; i < b.N; i++ { + router.ServeHTTP(nil, request) + } +} + +func BenchmarkMuxAlternativeInRegexp(b *testing.B) { + router := new(Router) + handler := func(w http.ResponseWriter, r *http.Request) {} + router.HandleFunc("/v1/{v1:(?:a|b)}", handler) + + requestA, _ := http.NewRequest("GET", "/v1/a", nil) + requestB, _ := http.NewRequest("GET", "/v1/b", nil) + for i := 0; i < b.N; i++ { + router.ServeHTTP(nil, requestA) + router.ServeHTTP(nil, requestB) + } +} + +func BenchmarkManyPathVariables(b *testing.B) { + router := new(Router) + handler := func(w http.ResponseWriter, r *http.Request) {} + router.HandleFunc("/v1/{v1}/{v2}/{v3}/{v4}/{v5}", handler) + + matchingRequest, _ := http.NewRequest("GET", "/v1/1/2/3/4/5", nil) + notMatchingRequest, _ := http.NewRequest("GET", "/v1/1/2/3/4", nil) + recorder := httptest.NewRecorder() + for i := 0; i < b.N; i++ { + router.ServeHTTP(nil, matchingRequest) + router.ServeHTTP(recorder, notMatchingRequest) + } +} diff --git a/contrib/backends/nntpchand/src/vendor/github.com/gorilla/mux/context_gorilla.go b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/mux/context_gorilla.go new file mode 100644 index 0000000..d7adaa8 --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/mux/context_gorilla.go @@ -0,0 +1,26 @@ +// +build !go1.7 + +package mux + +import ( + "net/http" + + "github.com/gorilla/context" +) + +func contextGet(r *http.Request, key interface{}) interface{} { + return context.Get(r, key) +} + +func contextSet(r *http.Request, key, val interface{}) *http.Request { + if val == nil { + return r + } + + context.Set(r, key, val) + return r +} + +func contextClear(r *http.Request) { + context.Clear(r) +} diff --git a/contrib/backends/nntpchand/src/vendor/github.com/gorilla/mux/context_gorilla_test.go b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/mux/context_gorilla_test.go new file mode 100644 index 0000000..ffaf384 --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/mux/context_gorilla_test.go @@ -0,0 +1,40 @@ +// +build !go1.7 + +package mux + +import ( + "net/http" + "testing" + + "github.com/gorilla/context" +) + +// Tests that the context is cleared or not cleared properly depending on +// the configuration of the router +func TestKeepContext(t *testing.T) { + func1 := func(w http.ResponseWriter, r *http.Request) {} + + r := NewRouter() + r.HandleFunc("/", func1).Name("func1") + + req, _ := http.NewRequest("GET", "http://localhost/", nil) + context.Set(req, "t", 1) + + res := new(http.ResponseWriter) + r.ServeHTTP(*res, req) + + if _, ok := context.GetOk(req, "t"); ok { + t.Error("Context should have been cleared at end of request") + } + + r.KeepContext = true + + req, _ = http.NewRequest("GET", "http://localhost/", nil) + context.Set(req, "t", 1) + + r.ServeHTTP(*res, req) + if _, ok := context.GetOk(req, "t"); !ok { + t.Error("Context should NOT have been cleared at end of request") + } + +} diff --git a/contrib/backends/nntpchand/src/vendor/github.com/gorilla/mux/context_native.go b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/mux/context_native.go new file mode 100644 index 0000000..209cbea --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/mux/context_native.go @@ -0,0 +1,24 @@ +// +build go1.7 + +package mux + +import ( + "context" + "net/http" +) + +func contextGet(r *http.Request, key interface{}) interface{} { + return r.Context().Value(key) +} + +func contextSet(r *http.Request, key, val interface{}) *http.Request { + if val == nil { + return r + } + + return r.WithContext(context.WithValue(r.Context(), key, val)) +} + +func contextClear(r *http.Request) { + return +} diff --git a/contrib/backends/nntpchand/src/vendor/github.com/gorilla/mux/context_native_test.go b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/mux/context_native_test.go new file mode 100644 index 0000000..c150edf --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/mux/context_native_test.go @@ -0,0 +1,32 @@ +// +build go1.7 + +package mux + +import ( + "context" + "net/http" + "testing" + "time" +) + +func TestNativeContextMiddleware(t *testing.T) { + withTimeout := func(h http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + ctx, cancel := context.WithTimeout(r.Context(), time.Minute) + defer cancel() + h.ServeHTTP(w, r.WithContext(ctx)) + }) + } + + r := NewRouter() + r.Handle("/path/{foo}", withTimeout(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + vars := Vars(r) + if vars["foo"] != "bar" { + t.Fatal("Expected foo var to be set") + } + }))) + + rec := NewRecorder() + req := newRequest("GET", "/path/bar") + r.ServeHTTP(rec, req) +} diff --git a/contrib/backends/nntpchand/src/vendor/github.com/gorilla/mux/doc.go b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/mux/doc.go new file mode 100644 index 0000000..00daf4a --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/mux/doc.go @@ -0,0 +1,240 @@ +// Copyright 2012 The Gorilla 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 mux implements a request router and dispatcher. + +The name mux stands for "HTTP request multiplexer". Like the standard +http.ServeMux, mux.Router matches incoming requests against a list of +registered routes and calls a handler for the route that matches the URL +or other conditions. The main features are: + + * Requests can be matched based on URL host, path, path prefix, schemes, + header and query values, HTTP methods or using custom matchers. + * URL hosts and paths can have variables with an optional regular + expression. + * Registered URLs can be built, or "reversed", which helps maintaining + references to resources. + * Routes can be used as subrouters: nested routes are only tested if the + parent route matches. This is useful to define groups of routes that + share common conditions like a host, a path prefix or other repeated + attributes. As a bonus, this optimizes request matching. + * It implements the http.Handler interface so it is compatible with the + standard http.ServeMux. + +Let's start registering a couple of URL paths and handlers: + + func main() { + r := mux.NewRouter() + r.HandleFunc("/", HomeHandler) + r.HandleFunc("/products", ProductsHandler) + r.HandleFunc("/articles", ArticlesHandler) + http.Handle("/", r) + } + +Here we register three routes mapping URL paths to handlers. This is +equivalent to how http.HandleFunc() works: if an incoming request URL matches +one of the paths, the corresponding handler is called passing +(http.ResponseWriter, *http.Request) as parameters. + +Paths can have variables. They are defined using the format {name} or +{name:pattern}. If a regular expression pattern is not defined, the matched +variable will be anything until the next slash. For example: + + r := mux.NewRouter() + r.HandleFunc("/products/{key}", ProductHandler) + r.HandleFunc("/articles/{category}/", ArticlesCategoryHandler) + r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler) + +Groups can be used inside patterns, as long as they are non-capturing (?:re). For example: + + r.HandleFunc("/articles/{category}/{sort:(?:asc|desc|new)}", ArticlesCategoryHandler) + +The names are used to create a map of route variables which can be retrieved +calling mux.Vars(): + + vars := mux.Vars(request) + category := vars["category"] + +Note that if any capturing groups are present, mux will panic() during parsing. To prevent +this, convert any capturing groups to non-capturing, e.g. change "/{sort:(asc|desc)}" to +"/{sort:(?:asc|desc)}". This is a change from prior versions which behaved unpredictably +when capturing groups were present. + +And this is all you need to know about the basic usage. More advanced options +are explained below. + +Routes can also be restricted to a domain or subdomain. Just define a host +pattern to be matched. They can also have variables: + + r := mux.NewRouter() + // Only matches if domain is "www.example.com". + r.Host("www.example.com") + // Matches a dynamic subdomain. + r.Host("{subdomain:[a-z]+}.domain.com") + +There are several other matchers that can be added. To match path prefixes: + + r.PathPrefix("/products/") + +...or HTTP methods: + + r.Methods("GET", "POST") + +...or URL schemes: + + r.Schemes("https") + +...or header values: + + r.Headers("X-Requested-With", "XMLHttpRequest") + +...or query values: + + r.Queries("key", "value") + +...or to use a custom matcher function: + + r.MatcherFunc(func(r *http.Request, rm *RouteMatch) bool { + return r.ProtoMajor == 0 + }) + +...and finally, it is possible to combine several matchers in a single route: + + r.HandleFunc("/products", ProductsHandler). + Host("www.example.com"). + Methods("GET"). + Schemes("http") + +Setting the same matching conditions again and again can be boring, so we have +a way to group several routes that share the same requirements. +We call it "subrouting". + +For example, let's say we have several URLs that should only match when the +host is "www.example.com". Create a route for that host and get a "subrouter" +from it: + + r := mux.NewRouter() + s := r.Host("www.example.com").Subrouter() + +Then register routes in the subrouter: + + s.HandleFunc("/products/", ProductsHandler) + s.HandleFunc("/products/{key}", ProductHandler) + s.HandleFunc("/articles/{category}/{id:[0-9]+}"), ArticleHandler) + +The three URL paths we registered above will only be tested if the domain is +"www.example.com", because the subrouter is tested first. This is not +only convenient, but also optimizes request matching. You can create +subrouters combining any attribute matchers accepted by a route. + +Subrouters can be used to create domain or path "namespaces": you define +subrouters in a central place and then parts of the app can register its +paths relatively to a given subrouter. + +There's one more thing about subroutes. When a subrouter has a path prefix, +the inner routes use it as base for their paths: + + r := mux.NewRouter() + s := r.PathPrefix("/products").Subrouter() + // "/products/" + s.HandleFunc("/", ProductsHandler) + // "/products/{key}/" + s.HandleFunc("/{key}/", ProductHandler) + // "/products/{key}/details" + s.HandleFunc("/{key}/details", ProductDetailsHandler) + +Note that the path provided to PathPrefix() represents a "wildcard": calling +PathPrefix("/static/").Handler(...) means that the handler will be passed any +request that matches "/static/*". This makes it easy to serve static files with mux: + + func main() { + var dir string + + flag.StringVar(&dir, "dir", ".", "the directory to serve files from. Defaults to the current dir") + flag.Parse() + r := mux.NewRouter() + + // This will serve files under http://localhost:8000/static/ + r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir(dir)))) + + srv := &http.Server{ + Handler: r, + Addr: "127.0.0.1:8000", + // Good practice: enforce timeouts for servers you create! + WriteTimeout: 15 * time.Second, + ReadTimeout: 15 * time.Second, + } + + log.Fatal(srv.ListenAndServe()) + } + +Now let's see how to build registered URLs. + +Routes can be named. All routes that define a name can have their URLs built, +or "reversed". We define a name calling Name() on a route. For example: + + r := mux.NewRouter() + r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler). + Name("article") + +To build a URL, get the route and call the URL() method, passing a sequence of +key/value pairs for the route variables. For the previous route, we would do: + + url, err := r.Get("article").URL("category", "technology", "id", "42") + +...and the result will be a url.URL with the following path: + + "/articles/technology/42" + +This also works for host variables: + + r := mux.NewRouter() + r.Host("{subdomain}.domain.com"). + Path("/articles/{category}/{id:[0-9]+}"). + HandlerFunc(ArticleHandler). + Name("article") + + // url.String() will be "http://news.domain.com/articles/technology/42" + url, err := r.Get("article").URL("subdomain", "news", + "category", "technology", + "id", "42") + +All variables defined in the route are required, and their values must +conform to the corresponding patterns. These requirements guarantee that a +generated URL will always match a registered route -- the only exception is +for explicitly defined "build-only" routes which never match. + +Regex support also exists for matching Headers within a route. For example, we could do: + + r.HeadersRegexp("Content-Type", "application/(text|json)") + +...and the route will match both requests with a Content-Type of `application/json` as well as +`application/text` + +There's also a way to build only the URL host or path for a route: +use the methods URLHost() or URLPath() instead. For the previous route, +we would do: + + // "http://news.domain.com/" + host, err := r.Get("article").URLHost("subdomain", "news") + + // "/articles/technology/42" + path, err := r.Get("article").URLPath("category", "technology", "id", "42") + +And if you use subrouters, host and path defined separately can be built +as well: + + r := mux.NewRouter() + s := r.Host("{subdomain}.domain.com").Subrouter() + s.Path("/articles/{category}/{id:[0-9]+}"). + HandlerFunc(ArticleHandler). + Name("article") + + // "http://news.domain.com/articles/technology/42" + url, err := r.Get("article").URL("subdomain", "news", + "category", "technology", + "id", "42") +*/ +package mux diff --git a/contrib/backends/nntpchand/src/vendor/github.com/gorilla/mux/mux.go b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/mux/mux.go new file mode 100644 index 0000000..d66ec38 --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/mux/mux.go @@ -0,0 +1,542 @@ +// Copyright 2012 The Gorilla 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 mux + +import ( + "errors" + "fmt" + "net/http" + "path" + "regexp" + "strings" +) + +// NewRouter returns a new router instance. +func NewRouter() *Router { + return &Router{namedRoutes: make(map[string]*Route), KeepContext: false} +} + +// Router registers routes to be matched and dispatches a handler. +// +// It implements the http.Handler interface, so it can be registered to serve +// requests: +// +// var router = mux.NewRouter() +// +// func main() { +// http.Handle("/", router) +// } +// +// Or, for Google App Engine, register it in a init() function: +// +// func init() { +// http.Handle("/", router) +// } +// +// This will send all incoming requests to the router. +type Router struct { + // Configurable Handler to be used when no route matches. + NotFoundHandler http.Handler + // Parent route, if this is a subrouter. + parent parentRoute + // Routes to be matched, in order. + routes []*Route + // Routes by name for URL building. + namedRoutes map[string]*Route + // See Router.StrictSlash(). This defines the flag for new routes. + strictSlash bool + // See Router.SkipClean(). This defines the flag for new routes. + skipClean bool + // If true, do not clear the request context after handling the request. + // This has no effect when go1.7+ is used, since the context is stored + // on the request itself. + KeepContext bool + // see Router.UseEncodedPath(). This defines a flag for all routes. + useEncodedPath bool +} + +// Match matches registered routes against the request. +func (r *Router) Match(req *http.Request, match *RouteMatch) bool { + for _, route := range r.routes { + if route.Match(req, match) { + return true + } + } + + // Closest match for a router (includes sub-routers) + if r.NotFoundHandler != nil { + match.Handler = r.NotFoundHandler + return true + } + return false +} + +// ServeHTTP dispatches the handler registered in the matched route. +// +// When there is a match, the route variables can be retrieved calling +// mux.Vars(request). +func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) { + if !r.skipClean { + path := req.URL.Path + if r.useEncodedPath { + path = getPath(req) + } + // Clean path to canonical form and redirect. + if p := cleanPath(path); p != path { + + // Added 3 lines (Philip Schlump) - It was dropping the query string and #whatever from query. + // This matches with fix in go 1.2 r.c. 4 for same problem. Go Issue: + // http://code.google.com/p/go/issues/detail?id=5252 + url := *req.URL + url.Path = p + p = url.String() + + w.Header().Set("Location", p) + w.WriteHeader(http.StatusMovedPermanently) + return + } + } + var match RouteMatch + var handler http.Handler + if r.Match(req, &match) { + handler = match.Handler + req = setVars(req, match.Vars) + req = setCurrentRoute(req, match.Route) + } + if handler == nil { + handler = http.NotFoundHandler() + } + if !r.KeepContext { + defer contextClear(req) + } + handler.ServeHTTP(w, req) +} + +// Get returns a route registered with the given name. +func (r *Router) Get(name string) *Route { + return r.getNamedRoutes()[name] +} + +// GetRoute returns a route registered with the given name. This method +// was renamed to Get() and remains here for backwards compatibility. +func (r *Router) GetRoute(name string) *Route { + return r.getNamedRoutes()[name] +} + +// StrictSlash defines the trailing slash behavior for new routes. The initial +// value is false. +// +// When true, if the route path is "/path/", accessing "/path" will redirect +// to the former and vice versa. In other words, your application will always +// see the path as specified in the route. +// +// When false, if the route path is "/path", accessing "/path/" will not match +// this route and vice versa. +// +// Special case: when a route sets a path prefix using the PathPrefix() method, +// strict slash is ignored for that route because the redirect behavior can't +// be determined from a prefix alone. However, any subrouters created from that +// route inherit the original StrictSlash setting. +func (r *Router) StrictSlash(value bool) *Router { + r.strictSlash = value + return r +} + +// SkipClean defines the path cleaning behaviour for new routes. The initial +// value is false. Users should be careful about which routes are not cleaned +// +// When true, if the route path is "/path//to", it will remain with the double +// slash. This is helpful if you have a route like: /fetch/http://xkcd.com/534/ +// +// When false, the path will be cleaned, so /fetch/http://xkcd.com/534/ will +// become /fetch/http/xkcd.com/534 +func (r *Router) SkipClean(value bool) *Router { + r.skipClean = value + return r +} + +// UseEncodedPath tells the router to match the encoded original path +// to the routes. +// For eg. "/path/foo%2Fbar/to" will match the path "/path/{var}/to". +// This behavior has the drawback of needing to match routes against +// r.RequestURI instead of r.URL.Path. Any modifications (such as http.StripPrefix) +// to r.URL.Path will not affect routing when this flag is on and thus may +// induce unintended behavior. +// +// If not called, the router will match the unencoded path to the routes. +// For eg. "/path/foo%2Fbar/to" will match the path "/path/foo/bar/to" +func (r *Router) UseEncodedPath() *Router { + r.useEncodedPath = true + return r +} + +// ---------------------------------------------------------------------------- +// parentRoute +// ---------------------------------------------------------------------------- + +// getNamedRoutes returns the map where named routes are registered. +func (r *Router) getNamedRoutes() map[string]*Route { + if r.namedRoutes == nil { + if r.parent != nil { + r.namedRoutes = r.parent.getNamedRoutes() + } else { + r.namedRoutes = make(map[string]*Route) + } + } + return r.namedRoutes +} + +// getRegexpGroup returns regexp definitions from the parent route, if any. +func (r *Router) getRegexpGroup() *routeRegexpGroup { + if r.parent != nil { + return r.parent.getRegexpGroup() + } + return nil +} + +func (r *Router) buildVars(m map[string]string) map[string]string { + if r.parent != nil { + m = r.parent.buildVars(m) + } + return m +} + +// ---------------------------------------------------------------------------- +// Route factories +// ---------------------------------------------------------------------------- + +// NewRoute registers an empty route. +func (r *Router) NewRoute() *Route { + route := &Route{parent: r, strictSlash: r.strictSlash, skipClean: r.skipClean, useEncodedPath: r.useEncodedPath} + r.routes = append(r.routes, route) + return route +} + +// Handle registers a new route with a matcher for the URL path. +// See Route.Path() and Route.Handler(). +func (r *Router) Handle(path string, handler http.Handler) *Route { + return r.NewRoute().Path(path).Handler(handler) +} + +// HandleFunc registers a new route with a matcher for the URL path. +// See Route.Path() and Route.HandlerFunc(). +func (r *Router) HandleFunc(path string, f func(http.ResponseWriter, + *http.Request)) *Route { + return r.NewRoute().Path(path).HandlerFunc(f) +} + +// Headers registers a new route with a matcher for request header values. +// See Route.Headers(). +func (r *Router) Headers(pairs ...string) *Route { + return r.NewRoute().Headers(pairs...) +} + +// Host registers a new route with a matcher for the URL host. +// See Route.Host(). +func (r *Router) Host(tpl string) *Route { + return r.NewRoute().Host(tpl) +} + +// MatcherFunc registers a new route with a custom matcher function. +// See Route.MatcherFunc(). +func (r *Router) MatcherFunc(f MatcherFunc) *Route { + return r.NewRoute().MatcherFunc(f) +} + +// Methods registers a new route with a matcher for HTTP methods. +// See Route.Methods(). +func (r *Router) Methods(methods ...string) *Route { + return r.NewRoute().Methods(methods...) +} + +// Path registers a new route with a matcher for the URL path. +// See Route.Path(). +func (r *Router) Path(tpl string) *Route { + return r.NewRoute().Path(tpl) +} + +// PathPrefix registers a new route with a matcher for the URL path prefix. +// See Route.PathPrefix(). +func (r *Router) PathPrefix(tpl string) *Route { + return r.NewRoute().PathPrefix(tpl) +} + +// Queries registers a new route with a matcher for URL query values. +// See Route.Queries(). +func (r *Router) Queries(pairs ...string) *Route { + return r.NewRoute().Queries(pairs...) +} + +// Schemes registers a new route with a matcher for URL schemes. +// See Route.Schemes(). +func (r *Router) Schemes(schemes ...string) *Route { + return r.NewRoute().Schemes(schemes...) +} + +// BuildVarsFunc registers a new route with a custom function for modifying +// route variables before building a URL. +func (r *Router) BuildVarsFunc(f BuildVarsFunc) *Route { + return r.NewRoute().BuildVarsFunc(f) +} + +// Walk walks the router and all its sub-routers, calling walkFn for each route +// in the tree. The routes are walked in the order they were added. Sub-routers +// are explored depth-first. +func (r *Router) Walk(walkFn WalkFunc) error { + return r.walk(walkFn, []*Route{}) +} + +// SkipRouter is used as a return value from WalkFuncs to indicate that the +// router that walk is about to descend down to should be skipped. +var SkipRouter = errors.New("skip this router") + +// WalkFunc is the type of the function called for each route visited by Walk. +// At every invocation, it is given the current route, and the current router, +// and a list of ancestor routes that lead to the current route. +type WalkFunc func(route *Route, router *Router, ancestors []*Route) error + +func (r *Router) walk(walkFn WalkFunc, ancestors []*Route) error { + for _, t := range r.routes { + if t.regexp == nil || t.regexp.path == nil || t.regexp.path.template == "" { + continue + } + + err := walkFn(t, r, ancestors) + if err == SkipRouter { + continue + } + if err != nil { + return err + } + for _, sr := range t.matchers { + if h, ok := sr.(*Router); ok { + err := h.walk(walkFn, ancestors) + if err != nil { + return err + } + } + } + if h, ok := t.handler.(*Router); ok { + ancestors = append(ancestors, t) + err := h.walk(walkFn, ancestors) + if err != nil { + return err + } + ancestors = ancestors[:len(ancestors)-1] + } + } + return nil +} + +// ---------------------------------------------------------------------------- +// Context +// ---------------------------------------------------------------------------- + +// RouteMatch stores information about a matched route. +type RouteMatch struct { + Route *Route + Handler http.Handler + Vars map[string]string +} + +type contextKey int + +const ( + varsKey contextKey = iota + routeKey +) + +// Vars returns the route variables for the current request, if any. +func Vars(r *http.Request) map[string]string { + if rv := contextGet(r, varsKey); rv != nil { + return rv.(map[string]string) + } + return nil +} + +// CurrentRoute returns the matched route for the current request, if any. +// This only works when called inside the handler of the matched route +// because the matched route is stored in the request context which is cleared +// after the handler returns, unless the KeepContext option is set on the +// Router. +func CurrentRoute(r *http.Request) *Route { + if rv := contextGet(r, routeKey); rv != nil { + return rv.(*Route) + } + return nil +} + +func setVars(r *http.Request, val interface{}) *http.Request { + return contextSet(r, varsKey, val) +} + +func setCurrentRoute(r *http.Request, val interface{}) *http.Request { + return contextSet(r, routeKey, val) +} + +// ---------------------------------------------------------------------------- +// Helpers +// ---------------------------------------------------------------------------- + +// getPath returns the escaped path if possible; doing what URL.EscapedPath() +// which was added in go1.5 does +func getPath(req *http.Request) string { + if req.RequestURI != "" { + // Extract the path from RequestURI (which is escaped unlike URL.Path) + // as detailed here as detailed in https://golang.org/pkg/net/url/#URL + // for < 1.5 server side workaround + // http://localhost/path/here?v=1 -> /path/here + path := req.RequestURI + path = strings.TrimPrefix(path, req.URL.Scheme+`://`) + path = strings.TrimPrefix(path, req.URL.Host) + if i := strings.LastIndex(path, "?"); i > -1 { + path = path[:i] + } + if i := strings.LastIndex(path, "#"); i > -1 { + path = path[:i] + } + return path + } + return req.URL.Path +} + +// cleanPath returns the canonical path for p, eliminating . and .. elements. +// Borrowed from the net/http package. +func cleanPath(p string) string { + if p == "" { + return "/" + } + if p[0] != '/' { + p = "/" + p + } + np := path.Clean(p) + // path.Clean removes trailing slash except for root; + // put the trailing slash back if necessary. + if p[len(p)-1] == '/' && np != "/" { + np += "/" + } + + return np +} + +// uniqueVars returns an error if two slices contain duplicated strings. +func uniqueVars(s1, s2 []string) error { + for _, v1 := range s1 { + for _, v2 := range s2 { + if v1 == v2 { + return fmt.Errorf("mux: duplicated route variable %q", v2) + } + } + } + return nil +} + +// checkPairs returns the count of strings passed in, and an error if +// the count is not an even number. +func checkPairs(pairs ...string) (int, error) { + length := len(pairs) + if length%2 != 0 { + return length, fmt.Errorf( + "mux: number of parameters must be multiple of 2, got %v", pairs) + } + return length, nil +} + +// mapFromPairsToString converts variadic string parameters to a +// string to string map. +func mapFromPairsToString(pairs ...string) (map[string]string, error) { + length, err := checkPairs(pairs...) + if err != nil { + return nil, err + } + m := make(map[string]string, length/2) + for i := 0; i < length; i += 2 { + m[pairs[i]] = pairs[i+1] + } + return m, nil +} + +// mapFromPairsToRegex converts variadic string paramers to a +// string to regex map. +func mapFromPairsToRegex(pairs ...string) (map[string]*regexp.Regexp, error) { + length, err := checkPairs(pairs...) + if err != nil { + return nil, err + } + m := make(map[string]*regexp.Regexp, length/2) + for i := 0; i < length; i += 2 { + regex, err := regexp.Compile(pairs[i+1]) + if err != nil { + return nil, err + } + m[pairs[i]] = regex + } + return m, nil +} + +// matchInArray returns true if the given string value is in the array. +func matchInArray(arr []string, value string) bool { + for _, v := range arr { + if v == value { + return true + } + } + return false +} + +// matchMapWithString returns true if the given key/value pairs exist in a given map. +func matchMapWithString(toCheck map[string]string, toMatch map[string][]string, canonicalKey bool) bool { + for k, v := range toCheck { + // Check if key exists. + if canonicalKey { + k = http.CanonicalHeaderKey(k) + } + if values := toMatch[k]; values == nil { + return false + } else if v != "" { + // If value was defined as an empty string we only check that the + // key exists. Otherwise we also check for equality. + valueExists := false + for _, value := range values { + if v == value { + valueExists = true + break + } + } + if !valueExists { + return false + } + } + } + return true +} + +// matchMapWithRegex returns true if the given key/value pairs exist in a given map compiled against +// the given regex +func matchMapWithRegex(toCheck map[string]*regexp.Regexp, toMatch map[string][]string, canonicalKey bool) bool { + for k, v := range toCheck { + // Check if key exists. + if canonicalKey { + k = http.CanonicalHeaderKey(k) + } + if values := toMatch[k]; values == nil { + return false + } else if v != nil { + // If value was defined as an empty string we only check that the + // key exists. Otherwise we also check for equality. + valueExists := false + for _, value := range values { + if v.MatchString(value) { + valueExists = true + break + } + } + if !valueExists { + return false + } + } + } + return true +} diff --git a/contrib/backends/nntpchand/src/vendor/github.com/gorilla/mux/mux_test.go b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/mux/mux_test.go new file mode 100644 index 0000000..405aca6 --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/mux/mux_test.go @@ -0,0 +1,1655 @@ +// Copyright 2012 The Gorilla 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 mux + +import ( + "bufio" + "bytes" + "errors" + "fmt" + "net/http" + "strings" + "testing" +) + +func (r *Route) GoString() string { + matchers := make([]string, len(r.matchers)) + for i, m := range r.matchers { + matchers[i] = fmt.Sprintf("%#v", m) + } + return fmt.Sprintf("&Route{matchers:[]matcher{%s}}", strings.Join(matchers, ", ")) +} + +func (r *routeRegexp) GoString() string { + return fmt.Sprintf("&routeRegexp{template: %q, matchHost: %t, matchQuery: %t, strictSlash: %t, regexp: regexp.MustCompile(%q), reverse: %q, varsN: %v, varsR: %v", r.template, r.matchHost, r.matchQuery, r.strictSlash, r.regexp.String(), r.reverse, r.varsN, r.varsR) +} + +type routeTest struct { + title string // title of the test + route *Route // the route being tested + request *http.Request // a request to test the route + vars map[string]string // the expected vars of the match + host string // the expected host of the match + path string // the expected path of the match + pathTemplate string // the expected path template to match + hostTemplate string // the expected host template to match + shouldMatch bool // whether the request is expected to match the route at all + shouldRedirect bool // whether the request should result in a redirect +} + +func TestHost(t *testing.T) { + // newRequestHost a new request with a method, url, and host header + newRequestHost := func(method, url, host string) *http.Request { + req, err := http.NewRequest(method, url, nil) + if err != nil { + panic(err) + } + req.Host = host + return req + } + + tests := []routeTest{ + { + title: "Host route match", + route: new(Route).Host("aaa.bbb.ccc"), + request: newRequest("GET", "http://aaa.bbb.ccc/111/222/333"), + vars: map[string]string{}, + host: "aaa.bbb.ccc", + path: "", + shouldMatch: true, + }, + { + title: "Host route, wrong host in request URL", + route: new(Route).Host("aaa.bbb.ccc"), + request: newRequest("GET", "http://aaa.222.ccc/111/222/333"), + vars: map[string]string{}, + host: "aaa.bbb.ccc", + path: "", + shouldMatch: false, + }, + { + title: "Host route with port, match", + route: new(Route).Host("aaa.bbb.ccc:1234"), + request: newRequest("GET", "http://aaa.bbb.ccc:1234/111/222/333"), + vars: map[string]string{}, + host: "aaa.bbb.ccc:1234", + path: "", + shouldMatch: true, + }, + { + title: "Host route with port, wrong port in request URL", + route: new(Route).Host("aaa.bbb.ccc:1234"), + request: newRequest("GET", "http://aaa.bbb.ccc:9999/111/222/333"), + vars: map[string]string{}, + host: "aaa.bbb.ccc:1234", + path: "", + shouldMatch: false, + }, + { + title: "Host route, match with host in request header", + route: new(Route).Host("aaa.bbb.ccc"), + request: newRequestHost("GET", "/111/222/333", "aaa.bbb.ccc"), + vars: map[string]string{}, + host: "aaa.bbb.ccc", + path: "", + shouldMatch: true, + }, + { + title: "Host route, wrong host in request header", + route: new(Route).Host("aaa.bbb.ccc"), + request: newRequestHost("GET", "/111/222/333", "aaa.222.ccc"), + vars: map[string]string{}, + host: "aaa.bbb.ccc", + path: "", + shouldMatch: false, + }, + // BUG {new(Route).Host("aaa.bbb.ccc:1234"), newRequestHost("GET", "/111/222/333", "aaa.bbb.ccc:1234"), map[string]string{}, "aaa.bbb.ccc:1234", "", true}, + { + title: "Host route with port, wrong host in request header", + route: new(Route).Host("aaa.bbb.ccc:1234"), + request: newRequestHost("GET", "/111/222/333", "aaa.bbb.ccc:9999"), + vars: map[string]string{}, + host: "aaa.bbb.ccc:1234", + path: "", + shouldMatch: false, + }, + { + title: "Host route with pattern, match", + route: new(Route).Host("aaa.{v1:[a-z]{3}}.ccc"), + request: newRequest("GET", "http://aaa.bbb.ccc/111/222/333"), + vars: map[string]string{"v1": "bbb"}, + host: "aaa.bbb.ccc", + path: "", + hostTemplate: `aaa.{v1:[a-z]{3}}.ccc`, + shouldMatch: true, + }, + { + title: "Host route with pattern, additional capturing group, match", + route: new(Route).Host("aaa.{v1:[a-z]{2}(?:b|c)}.ccc"), + request: newRequest("GET", "http://aaa.bbb.ccc/111/222/333"), + vars: map[string]string{"v1": "bbb"}, + host: "aaa.bbb.ccc", + path: "", + hostTemplate: `aaa.{v1:[a-z]{2}(?:b|c)}.ccc`, + shouldMatch: true, + }, + { + title: "Host route with pattern, wrong host in request URL", + route: new(Route).Host("aaa.{v1:[a-z]{3}}.ccc"), + request: newRequest("GET", "http://aaa.222.ccc/111/222/333"), + vars: map[string]string{"v1": "bbb"}, + host: "aaa.bbb.ccc", + path: "", + hostTemplate: `aaa.{v1:[a-z]{3}}.ccc`, + shouldMatch: false, + }, + { + title: "Host route with multiple patterns, match", + route: new(Route).Host("{v1:[a-z]{3}}.{v2:[a-z]{3}}.{v3:[a-z]{3}}"), + request: newRequest("GET", "http://aaa.bbb.ccc/111/222/333"), + vars: map[string]string{"v1": "aaa", "v2": "bbb", "v3": "ccc"}, + host: "aaa.bbb.ccc", + path: "", + hostTemplate: `{v1:[a-z]{3}}.{v2:[a-z]{3}}.{v3:[a-z]{3}}`, + shouldMatch: true, + }, + { + title: "Host route with multiple patterns, wrong host in request URL", + route: new(Route).Host("{v1:[a-z]{3}}.{v2:[a-z]{3}}.{v3:[a-z]{3}}"), + request: newRequest("GET", "http://aaa.222.ccc/111/222/333"), + vars: map[string]string{"v1": "aaa", "v2": "bbb", "v3": "ccc"}, + host: "aaa.bbb.ccc", + path: "", + hostTemplate: `{v1:[a-z]{3}}.{v2:[a-z]{3}}.{v3:[a-z]{3}}`, + shouldMatch: false, + }, + { + title: "Host route with hyphenated name and pattern, match", + route: new(Route).Host("aaa.{v-1:[a-z]{3}}.ccc"), + request: newRequest("GET", "http://aaa.bbb.ccc/111/222/333"), + vars: map[string]string{"v-1": "bbb"}, + host: "aaa.bbb.ccc", + path: "", + hostTemplate: `aaa.{v-1:[a-z]{3}}.ccc`, + shouldMatch: true, + }, + { + title: "Host route with hyphenated name and pattern, additional capturing group, match", + route: new(Route).Host("aaa.{v-1:[a-z]{2}(?:b|c)}.ccc"), + request: newRequest("GET", "http://aaa.bbb.ccc/111/222/333"), + vars: map[string]string{"v-1": "bbb"}, + host: "aaa.bbb.ccc", + path: "", + hostTemplate: `aaa.{v-1:[a-z]{2}(?:b|c)}.ccc`, + shouldMatch: true, + }, + { + title: "Host route with multiple hyphenated names and patterns, match", + route: new(Route).Host("{v-1:[a-z]{3}}.{v-2:[a-z]{3}}.{v-3:[a-z]{3}}"), + request: newRequest("GET", "http://aaa.bbb.ccc/111/222/333"), + vars: map[string]string{"v-1": "aaa", "v-2": "bbb", "v-3": "ccc"}, + host: "aaa.bbb.ccc", + path: "", + hostTemplate: `{v-1:[a-z]{3}}.{v-2:[a-z]{3}}.{v-3:[a-z]{3}}`, + shouldMatch: true, + }, + { + title: "Path route with single pattern with pipe, match", + route: new(Route).Path("/{category:a|b/c}"), + request: newRequest("GET", "http://localhost/a"), + vars: map[string]string{"category": "a"}, + host: "", + path: "/a", + pathTemplate: `/{category:a|b/c}`, + shouldMatch: true, + }, + { + title: "Path route with single pattern with pipe, match", + route: new(Route).Path("/{category:a|b/c}"), + request: newRequest("GET", "http://localhost/b/c"), + vars: map[string]string{"category": "b/c"}, + host: "", + path: "/b/c", + pathTemplate: `/{category:a|b/c}`, + shouldMatch: true, + }, + { + title: "Path route with multiple patterns with pipe, match", + route: new(Route).Path("/{category:a|b/c}/{product}/{id:[0-9]+}"), + request: newRequest("GET", "http://localhost/a/product_name/1"), + vars: map[string]string{"category": "a", "product": "product_name", "id": "1"}, + host: "", + path: "/a/product_name/1", + pathTemplate: `/{category:a|b/c}/{product}/{id:[0-9]+}`, + shouldMatch: true, + }, + { + title: "Path route with multiple patterns with pipe, match", + route: new(Route).Path("/{category:a|b/c}/{product}/{id:[0-9]+}"), + request: newRequest("GET", "http://localhost/b/c/product_name/1"), + vars: map[string]string{"category": "b/c", "product": "product_name", "id": "1"}, + host: "", + path: "/b/c/product_name/1", + pathTemplate: `/{category:a|b/c}/{product}/{id:[0-9]+}`, + shouldMatch: true, + }, + } + for _, test := range tests { + testRoute(t, test) + testTemplate(t, test) + } +} + +func TestPath(t *testing.T) { + tests := []routeTest{ + { + title: "Path route, match", + route: new(Route).Path("/111/222/333"), + request: newRequest("GET", "http://localhost/111/222/333"), + vars: map[string]string{}, + host: "", + path: "/111/222/333", + shouldMatch: true, + }, + { + title: "Path route, match with trailing slash in request and path", + route: new(Route).Path("/111/"), + request: newRequest("GET", "http://localhost/111/"), + vars: map[string]string{}, + host: "", + path: "/111/", + shouldMatch: true, + }, + { + title: "Path route, do not match with trailing slash in path", + route: new(Route).Path("/111/"), + request: newRequest("GET", "http://localhost/111"), + vars: map[string]string{}, + host: "", + path: "/111", + pathTemplate: `/111/`, + shouldMatch: false, + }, + { + title: "Path route, do not match with trailing slash in request", + route: new(Route).Path("/111"), + request: newRequest("GET", "http://localhost/111/"), + vars: map[string]string{}, + host: "", + path: "/111/", + pathTemplate: `/111`, + shouldMatch: false, + }, + { + title: "Path route, match root with no host", + route: new(Route).Path("/"), + request: newRequest("GET", "/"), + vars: map[string]string{}, + host: "", + path: "/", + pathTemplate: `/`, + shouldMatch: true, + }, + { + title: "Path route, match root with no host, App Engine format", + route: new(Route).Path("/"), + request: func() *http.Request { + r := newRequest("GET", "http://localhost/") + r.RequestURI = "/" + return r + }(), + vars: map[string]string{}, + host: "", + path: "/", + pathTemplate: `/`, + shouldMatch: true, + }, + { + title: "Path route, wrong path in request in request URL", + route: new(Route).Path("/111/222/333"), + request: newRequest("GET", "http://localhost/1/2/3"), + vars: map[string]string{}, + host: "", + path: "/111/222/333", + shouldMatch: false, + }, + { + title: "Path route with pattern, match", + route: new(Route).Path("/111/{v1:[0-9]{3}}/333"), + request: newRequest("GET", "http://localhost/111/222/333"), + vars: map[string]string{"v1": "222"}, + host: "", + path: "/111/222/333", + pathTemplate: `/111/{v1:[0-9]{3}}/333`, + shouldMatch: true, + }, + { + title: "Path route with pattern, URL in request does not match", + route: new(Route).Path("/111/{v1:[0-9]{3}}/333"), + request: newRequest("GET", "http://localhost/111/aaa/333"), + vars: map[string]string{"v1": "222"}, + host: "", + path: "/111/222/333", + pathTemplate: `/111/{v1:[0-9]{3}}/333`, + shouldMatch: false, + }, + { + title: "Path route with multiple patterns, match", + route: new(Route).Path("/{v1:[0-9]{3}}/{v2:[0-9]{3}}/{v3:[0-9]{3}}"), + request: newRequest("GET", "http://localhost/111/222/333"), + vars: map[string]string{"v1": "111", "v2": "222", "v3": "333"}, + host: "", + path: "/111/222/333", + pathTemplate: `/{v1:[0-9]{3}}/{v2:[0-9]{3}}/{v3:[0-9]{3}}`, + shouldMatch: true, + }, + { + title: "Path route with multiple patterns, URL in request does not match", + route: new(Route).Path("/{v1:[0-9]{3}}/{v2:[0-9]{3}}/{v3:[0-9]{3}}"), + request: newRequest("GET", "http://localhost/111/aaa/333"), + vars: map[string]string{"v1": "111", "v2": "222", "v3": "333"}, + host: "", + path: "/111/222/333", + pathTemplate: `/{v1:[0-9]{3}}/{v2:[0-9]{3}}/{v3:[0-9]{3}}`, + shouldMatch: false, + }, + { + title: "Path route with multiple patterns with pipe, match", + route: new(Route).Path("/{category:a|(?:b/c)}/{product}/{id:[0-9]+}"), + request: newRequest("GET", "http://localhost/a/product_name/1"), + vars: map[string]string{"category": "a", "product": "product_name", "id": "1"}, + host: "", + path: "/a/product_name/1", + pathTemplate: `/{category:a|(?:b/c)}/{product}/{id:[0-9]+}`, + shouldMatch: true, + }, + { + title: "Path route with hyphenated name and pattern, match", + route: new(Route).Path("/111/{v-1:[0-9]{3}}/333"), + request: newRequest("GET", "http://localhost/111/222/333"), + vars: map[string]string{"v-1": "222"}, + host: "", + path: "/111/222/333", + pathTemplate: `/111/{v-1:[0-9]{3}}/333`, + shouldMatch: true, + }, + { + title: "Path route with multiple hyphenated names and patterns, match", + route: new(Route).Path("/{v-1:[0-9]{3}}/{v-2:[0-9]{3}}/{v-3:[0-9]{3}}"), + request: newRequest("GET", "http://localhost/111/222/333"), + vars: map[string]string{"v-1": "111", "v-2": "222", "v-3": "333"}, + host: "", + path: "/111/222/333", + pathTemplate: `/{v-1:[0-9]{3}}/{v-2:[0-9]{3}}/{v-3:[0-9]{3}}`, + shouldMatch: true, + }, + { + title: "Path route with multiple hyphenated names and patterns with pipe, match", + route: new(Route).Path("/{product-category:a|(?:b/c)}/{product-name}/{product-id:[0-9]+}"), + request: newRequest("GET", "http://localhost/a/product_name/1"), + vars: map[string]string{"product-category": "a", "product-name": "product_name", "product-id": "1"}, + host: "", + path: "/a/product_name/1", + pathTemplate: `/{product-category:a|(?:b/c)}/{product-name}/{product-id:[0-9]+}`, + shouldMatch: true, + }, + { + title: "Path route with multiple hyphenated names and patterns with pipe and case insensitive, match", + route: new(Route).Path("/{type:(?i:daily|mini|variety)}-{date:\\d{4,4}-\\d{2,2}-\\d{2,2}}"), + request: newRequest("GET", "http://localhost/daily-2016-01-01"), + vars: map[string]string{"type": "daily", "date": "2016-01-01"}, + host: "", + path: "/daily-2016-01-01", + pathTemplate: `/{type:(?i:daily|mini|variety)}-{date:\d{4,4}-\d{2,2}-\d{2,2}}`, + shouldMatch: true, + }, + { + title: "Path route with empty match right after other match", + route: new(Route).Path(`/{v1:[0-9]*}{v2:[a-z]*}/{v3:[0-9]*}`), + request: newRequest("GET", "http://localhost/111/222"), + vars: map[string]string{"v1": "111", "v2": "", "v3": "222"}, + host: "", + path: "/111/222", + pathTemplate: `/{v1:[0-9]*}{v2:[a-z]*}/{v3:[0-9]*}`, + shouldMatch: true, + }, + } + + for _, test := range tests { + testRoute(t, test) + testTemplate(t, test) + testUseEscapedRoute(t, test) + } +} + +func TestPathPrefix(t *testing.T) { + tests := []routeTest{ + { + title: "PathPrefix route, match", + route: new(Route).PathPrefix("/111"), + request: newRequest("GET", "http://localhost/111/222/333"), + vars: map[string]string{}, + host: "", + path: "/111", + shouldMatch: true, + }, + { + title: "PathPrefix route, match substring", + route: new(Route).PathPrefix("/1"), + request: newRequest("GET", "http://localhost/111/222/333"), + vars: map[string]string{}, + host: "", + path: "/1", + shouldMatch: true, + }, + { + title: "PathPrefix route, URL prefix in request does not match", + route: new(Route).PathPrefix("/111"), + request: newRequest("GET", "http://localhost/1/2/3"), + vars: map[string]string{}, + host: "", + path: "/111", + shouldMatch: false, + }, + { + title: "PathPrefix route with pattern, match", + route: new(Route).PathPrefix("/111/{v1:[0-9]{3}}"), + request: newRequest("GET", "http://localhost/111/222/333"), + vars: map[string]string{"v1": "222"}, + host: "", + path: "/111/222", + pathTemplate: `/111/{v1:[0-9]{3}}`, + shouldMatch: true, + }, + { + title: "PathPrefix route with pattern, URL prefix in request does not match", + route: new(Route).PathPrefix("/111/{v1:[0-9]{3}}"), + request: newRequest("GET", "http://localhost/111/aaa/333"), + vars: map[string]string{"v1": "222"}, + host: "", + path: "/111/222", + pathTemplate: `/111/{v1:[0-9]{3}}`, + shouldMatch: false, + }, + { + title: "PathPrefix route with multiple patterns, match", + route: new(Route).PathPrefix("/{v1:[0-9]{3}}/{v2:[0-9]{3}}"), + request: newRequest("GET", "http://localhost/111/222/333"), + vars: map[string]string{"v1": "111", "v2": "222"}, + host: "", + path: "/111/222", + pathTemplate: `/{v1:[0-9]{3}}/{v2:[0-9]{3}}`, + shouldMatch: true, + }, + { + title: "PathPrefix route with multiple patterns, URL prefix in request does not match", + route: new(Route).PathPrefix("/{v1:[0-9]{3}}/{v2:[0-9]{3}}"), + request: newRequest("GET", "http://localhost/111/aaa/333"), + vars: map[string]string{"v1": "111", "v2": "222"}, + host: "", + path: "/111/222", + pathTemplate: `/{v1:[0-9]{3}}/{v2:[0-9]{3}}`, + shouldMatch: false, + }, + } + + for _, test := range tests { + testRoute(t, test) + testTemplate(t, test) + testUseEscapedRoute(t, test) + } +} + +func TestHostPath(t *testing.T) { + tests := []routeTest{ + { + title: "Host and Path route, match", + route: new(Route).Host("aaa.bbb.ccc").Path("/111/222/333"), + request: newRequest("GET", "http://aaa.bbb.ccc/111/222/333"), + vars: map[string]string{}, + host: "", + path: "", + pathTemplate: `/111/222/333`, + hostTemplate: `aaa.bbb.ccc`, + shouldMatch: true, + }, + { + title: "Host and Path route, wrong host in request URL", + route: new(Route).Host("aaa.bbb.ccc").Path("/111/222/333"), + request: newRequest("GET", "http://aaa.222.ccc/111/222/333"), + vars: map[string]string{}, + host: "", + path: "", + pathTemplate: `/111/222/333`, + hostTemplate: `aaa.bbb.ccc`, + shouldMatch: false, + }, + { + title: "Host and Path route with pattern, match", + route: new(Route).Host("aaa.{v1:[a-z]{3}}.ccc").Path("/111/{v2:[0-9]{3}}/333"), + request: newRequest("GET", "http://aaa.bbb.ccc/111/222/333"), + vars: map[string]string{"v1": "bbb", "v2": "222"}, + host: "aaa.bbb.ccc", + path: "/111/222/333", + pathTemplate: `/111/{v2:[0-9]{3}}/333`, + hostTemplate: `aaa.{v1:[a-z]{3}}.ccc`, + shouldMatch: true, + }, + { + title: "Host and Path route with pattern, URL in request does not match", + route: new(Route).Host("aaa.{v1:[a-z]{3}}.ccc").Path("/111/{v2:[0-9]{3}}/333"), + request: newRequest("GET", "http://aaa.222.ccc/111/222/333"), + vars: map[string]string{"v1": "bbb", "v2": "222"}, + host: "aaa.bbb.ccc", + path: "/111/222/333", + pathTemplate: `/111/{v2:[0-9]{3}}/333`, + hostTemplate: `aaa.{v1:[a-z]{3}}.ccc`, + shouldMatch: false, + }, + { + title: "Host and Path route with multiple patterns, match", + route: new(Route).Host("{v1:[a-z]{3}}.{v2:[a-z]{3}}.{v3:[a-z]{3}}").Path("/{v4:[0-9]{3}}/{v5:[0-9]{3}}/{v6:[0-9]{3}}"), + request: newRequest("GET", "http://aaa.bbb.ccc/111/222/333"), + vars: map[string]string{"v1": "aaa", "v2": "bbb", "v3": "ccc", "v4": "111", "v5": "222", "v6": "333"}, + host: "aaa.bbb.ccc", + path: "/111/222/333", + pathTemplate: `/{v4:[0-9]{3}}/{v5:[0-9]{3}}/{v6:[0-9]{3}}`, + hostTemplate: `{v1:[a-z]{3}}.{v2:[a-z]{3}}.{v3:[a-z]{3}}`, + shouldMatch: true, + }, + { + title: "Host and Path route with multiple patterns, URL in request does not match", + route: new(Route).Host("{v1:[a-z]{3}}.{v2:[a-z]{3}}.{v3:[a-z]{3}}").Path("/{v4:[0-9]{3}}/{v5:[0-9]{3}}/{v6:[0-9]{3}}"), + request: newRequest("GET", "http://aaa.222.ccc/111/222/333"), + vars: map[string]string{"v1": "aaa", "v2": "bbb", "v3": "ccc", "v4": "111", "v5": "222", "v6": "333"}, + host: "aaa.bbb.ccc", + path: "/111/222/333", + pathTemplate: `/{v4:[0-9]{3}}/{v5:[0-9]{3}}/{v6:[0-9]{3}}`, + hostTemplate: `{v1:[a-z]{3}}.{v2:[a-z]{3}}.{v3:[a-z]{3}}`, + shouldMatch: false, + }, + } + + for _, test := range tests { + testRoute(t, test) + testTemplate(t, test) + testUseEscapedRoute(t, test) + } +} + +func TestHeaders(t *testing.T) { + // newRequestHeaders creates a new request with a method, url, and headers + newRequestHeaders := func(method, url string, headers map[string]string) *http.Request { + req, err := http.NewRequest(method, url, nil) + if err != nil { + panic(err) + } + for k, v := range headers { + req.Header.Add(k, v) + } + return req + } + + tests := []routeTest{ + { + title: "Headers route, match", + route: new(Route).Headers("foo", "bar", "baz", "ding"), + request: newRequestHeaders("GET", "http://localhost", map[string]string{"foo": "bar", "baz": "ding"}), + vars: map[string]string{}, + host: "", + path: "", + shouldMatch: true, + }, + { + title: "Headers route, bad header values", + route: new(Route).Headers("foo", "bar", "baz", "ding"), + request: newRequestHeaders("GET", "http://localhost", map[string]string{"foo": "bar", "baz": "dong"}), + vars: map[string]string{}, + host: "", + path: "", + shouldMatch: false, + }, + { + title: "Headers route, regex header values to match", + route: new(Route).Headers("foo", "ba[zr]"), + request: newRequestHeaders("GET", "http://localhost", map[string]string{"foo": "bar"}), + vars: map[string]string{}, + host: "", + path: "", + shouldMatch: false, + }, + { + title: "Headers route, regex header values to match", + route: new(Route).HeadersRegexp("foo", "ba[zr]"), + request: newRequestHeaders("GET", "http://localhost", map[string]string{"foo": "baz"}), + vars: map[string]string{}, + host: "", + path: "", + shouldMatch: true, + }, + } + + for _, test := range tests { + testRoute(t, test) + testTemplate(t, test) + } + +} + +func TestMethods(t *testing.T) { + tests := []routeTest{ + { + title: "Methods route, match GET", + route: new(Route).Methods("GET", "POST"), + request: newRequest("GET", "http://localhost"), + vars: map[string]string{}, + host: "", + path: "", + shouldMatch: true, + }, + { + title: "Methods route, match POST", + route: new(Route).Methods("GET", "POST"), + request: newRequest("POST", "http://localhost"), + vars: map[string]string{}, + host: "", + path: "", + shouldMatch: true, + }, + { + title: "Methods route, bad method", + route: new(Route).Methods("GET", "POST"), + request: newRequest("PUT", "http://localhost"), + vars: map[string]string{}, + host: "", + path: "", + shouldMatch: false, + }, + } + + for _, test := range tests { + testRoute(t, test) + testTemplate(t, test) + } +} + +func TestQueries(t *testing.T) { + tests := []routeTest{ + { + title: "Queries route, match", + route: new(Route).Queries("foo", "bar", "baz", "ding"), + request: newRequest("GET", "http://localhost?foo=bar&baz=ding"), + vars: map[string]string{}, + host: "", + path: "", + shouldMatch: true, + }, + { + title: "Queries route, match with a query string", + route: new(Route).Host("www.example.com").Path("/api").Queries("foo", "bar", "baz", "ding"), + request: newRequest("GET", "http://www.example.com/api?foo=bar&baz=ding"), + vars: map[string]string{}, + host: "", + path: "", + pathTemplate: `/api`, + hostTemplate: `www.example.com`, + shouldMatch: true, + }, + { + title: "Queries route, match with a query string out of order", + route: new(Route).Host("www.example.com").Path("/api").Queries("foo", "bar", "baz", "ding"), + request: newRequest("GET", "http://www.example.com/api?baz=ding&foo=bar"), + vars: map[string]string{}, + host: "", + path: "", + pathTemplate: `/api`, + hostTemplate: `www.example.com`, + shouldMatch: true, + }, + { + title: "Queries route, bad query", + route: new(Route).Queries("foo", "bar", "baz", "ding"), + request: newRequest("GET", "http://localhost?foo=bar&baz=dong"), + vars: map[string]string{}, + host: "", + path: "", + shouldMatch: false, + }, + { + title: "Queries route with pattern, match", + route: new(Route).Queries("foo", "{v1}"), + request: newRequest("GET", "http://localhost?foo=bar"), + vars: map[string]string{"v1": "bar"}, + host: "", + path: "", + shouldMatch: true, + }, + { + title: "Queries route with multiple patterns, match", + route: new(Route).Queries("foo", "{v1}", "baz", "{v2}"), + request: newRequest("GET", "http://localhost?foo=bar&baz=ding"), + vars: map[string]string{"v1": "bar", "v2": "ding"}, + host: "", + path: "", + shouldMatch: true, + }, + { + title: "Queries route with regexp pattern, match", + route: new(Route).Queries("foo", "{v1:[0-9]+}"), + request: newRequest("GET", "http://localhost?foo=10"), + vars: map[string]string{"v1": "10"}, + host: "", + path: "", + shouldMatch: true, + }, + { + title: "Queries route with regexp pattern, regexp does not match", + route: new(Route).Queries("foo", "{v1:[0-9]+}"), + request: newRequest("GET", "http://localhost?foo=a"), + vars: map[string]string{}, + host: "", + path: "", + shouldMatch: false, + }, + { + title: "Queries route with regexp pattern with quantifier, match", + route: new(Route).Queries("foo", "{v1:[0-9]{1}}"), + request: newRequest("GET", "http://localhost?foo=1"), + vars: map[string]string{"v1": "1"}, + host: "", + path: "", + shouldMatch: true, + }, + { + title: "Queries route with regexp pattern with quantifier, additional variable in query string, match", + route: new(Route).Queries("foo", "{v1:[0-9]{1}}"), + request: newRequest("GET", "http://localhost?bar=2&foo=1"), + vars: map[string]string{"v1": "1"}, + host: "", + path: "", + shouldMatch: true, + }, + { + title: "Queries route with regexp pattern with quantifier, regexp does not match", + route: new(Route).Queries("foo", "{v1:[0-9]{1}}"), + request: newRequest("GET", "http://localhost?foo=12"), + vars: map[string]string{}, + host: "", + path: "", + shouldMatch: false, + }, + { + title: "Queries route with regexp pattern with quantifier, additional capturing group", + route: new(Route).Queries("foo", "{v1:[0-9]{1}(?:a|b)}"), + request: newRequest("GET", "http://localhost?foo=1a"), + vars: map[string]string{"v1": "1a"}, + host: "", + path: "", + shouldMatch: true, + }, + { + title: "Queries route with regexp pattern with quantifier, additional variable in query string, regexp does not match", + route: new(Route).Queries("foo", "{v1:[0-9]{1}}"), + request: newRequest("GET", "http://localhost?foo=12"), + vars: map[string]string{}, + host: "", + path: "", + shouldMatch: false, + }, + { + title: "Queries route with hyphenated name, match", + route: new(Route).Queries("foo", "{v-1}"), + request: newRequest("GET", "http://localhost?foo=bar"), + vars: map[string]string{"v-1": "bar"}, + host: "", + path: "", + shouldMatch: true, + }, + { + title: "Queries route with multiple hyphenated names, match", + route: new(Route).Queries("foo", "{v-1}", "baz", "{v-2}"), + request: newRequest("GET", "http://localhost?foo=bar&baz=ding"), + vars: map[string]string{"v-1": "bar", "v-2": "ding"}, + host: "", + path: "", + shouldMatch: true, + }, + { + title: "Queries route with hyphenate name and pattern, match", + route: new(Route).Queries("foo", "{v-1:[0-9]+}"), + request: newRequest("GET", "http://localhost?foo=10"), + vars: map[string]string{"v-1": "10"}, + host: "", + path: "", + shouldMatch: true, + }, + { + title: "Queries route with hyphenated name and pattern with quantifier, additional capturing group", + route: new(Route).Queries("foo", "{v-1:[0-9]{1}(?:a|b)}"), + request: newRequest("GET", "http://localhost?foo=1a"), + vars: map[string]string{"v-1": "1a"}, + host: "", + path: "", + shouldMatch: true, + }, + { + title: "Queries route with empty value, should match", + route: new(Route).Queries("foo", ""), + request: newRequest("GET", "http://localhost?foo=bar"), + vars: map[string]string{}, + host: "", + path: "", + shouldMatch: true, + }, + { + title: "Queries route with empty value and no parameter in request, should not match", + route: new(Route).Queries("foo", ""), + request: newRequest("GET", "http://localhost"), + vars: map[string]string{}, + host: "", + path: "", + shouldMatch: false, + }, + { + title: "Queries route with empty value and empty parameter in request, should match", + route: new(Route).Queries("foo", ""), + request: newRequest("GET", "http://localhost?foo="), + vars: map[string]string{}, + host: "", + path: "", + shouldMatch: true, + }, + { + title: "Queries route with overlapping value, should not match", + route: new(Route).Queries("foo", "bar"), + request: newRequest("GET", "http://localhost?foo=barfoo"), + vars: map[string]string{}, + host: "", + path: "", + shouldMatch: false, + }, + { + title: "Queries route with no parameter in request, should not match", + route: new(Route).Queries("foo", "{bar}"), + request: newRequest("GET", "http://localhost"), + vars: map[string]string{}, + host: "", + path: "", + shouldMatch: false, + }, + { + title: "Queries route with empty parameter in request, should match", + route: new(Route).Queries("foo", "{bar}"), + request: newRequest("GET", "http://localhost?foo="), + vars: map[string]string{"foo": ""}, + host: "", + path: "", + shouldMatch: true, + }, + { + title: "Queries route, bad submatch", + route: new(Route).Queries("foo", "bar", "baz", "ding"), + request: newRequest("GET", "http://localhost?fffoo=bar&baz=dingggg"), + vars: map[string]string{}, + host: "", + path: "", + shouldMatch: false, + }, + } + + for _, test := range tests { + testRoute(t, test) + testTemplate(t, test) + testUseEscapedRoute(t, test) + } +} + +func TestSchemes(t *testing.T) { + tests := []routeTest{ + // Schemes + { + title: "Schemes route, match https", + route: new(Route).Schemes("https", "ftp"), + request: newRequest("GET", "https://localhost"), + vars: map[string]string{}, + host: "", + path: "", + shouldMatch: true, + }, + { + title: "Schemes route, match ftp", + route: new(Route).Schemes("https", "ftp"), + request: newRequest("GET", "ftp://localhost"), + vars: map[string]string{}, + host: "", + path: "", + shouldMatch: true, + }, + { + title: "Schemes route, bad scheme", + route: new(Route).Schemes("https", "ftp"), + request: newRequest("GET", "http://localhost"), + vars: map[string]string{}, + host: "", + path: "", + shouldMatch: false, + }, + } + for _, test := range tests { + testRoute(t, test) + testTemplate(t, test) + } +} + +func TestMatcherFunc(t *testing.T) { + m := func(r *http.Request, m *RouteMatch) bool { + if r.URL.Host == "aaa.bbb.ccc" { + return true + } + return false + } + + tests := []routeTest{ + { + title: "MatchFunc route, match", + route: new(Route).MatcherFunc(m), + request: newRequest("GET", "http://aaa.bbb.ccc"), + vars: map[string]string{}, + host: "", + path: "", + shouldMatch: true, + }, + { + title: "MatchFunc route, non-match", + route: new(Route).MatcherFunc(m), + request: newRequest("GET", "http://aaa.222.ccc"), + vars: map[string]string{}, + host: "", + path: "", + shouldMatch: false, + }, + } + + for _, test := range tests { + testRoute(t, test) + testTemplate(t, test) + } +} + +func TestBuildVarsFunc(t *testing.T) { + tests := []routeTest{ + { + title: "BuildVarsFunc set on route", + route: new(Route).Path(`/111/{v1:\d}{v2:.*}`).BuildVarsFunc(func(vars map[string]string) map[string]string { + vars["v1"] = "3" + vars["v2"] = "a" + return vars + }), + request: newRequest("GET", "http://localhost/111/2"), + path: "/111/3a", + pathTemplate: `/111/{v1:\d}{v2:.*}`, + shouldMatch: true, + }, + { + title: "BuildVarsFunc set on route and parent route", + route: new(Route).PathPrefix(`/{v1:\d}`).BuildVarsFunc(func(vars map[string]string) map[string]string { + vars["v1"] = "2" + return vars + }).Subrouter().Path(`/{v2:\w}`).BuildVarsFunc(func(vars map[string]string) map[string]string { + vars["v2"] = "b" + return vars + }), + request: newRequest("GET", "http://localhost/1/a"), + path: "/2/b", + pathTemplate: `/{v1:\d}/{v2:\w}`, + shouldMatch: true, + }, + } + + for _, test := range tests { + testRoute(t, test) + testTemplate(t, test) + } +} + +func TestSubRouter(t *testing.T) { + subrouter1 := new(Route).Host("{v1:[a-z]+}.google.com").Subrouter() + subrouter2 := new(Route).PathPrefix("/foo/{v1}").Subrouter() + subrouter3 := new(Route).PathPrefix("/foo").Subrouter() + subrouter4 := new(Route).PathPrefix("/foo/bar").Subrouter() + subrouter5 := new(Route).PathPrefix("/{category}").Subrouter() + + tests := []routeTest{ + { + route: subrouter1.Path("/{v2:[a-z]+}"), + request: newRequest("GET", "http://aaa.google.com/bbb"), + vars: map[string]string{"v1": "aaa", "v2": "bbb"}, + host: "aaa.google.com", + path: "/bbb", + pathTemplate: `/{v2:[a-z]+}`, + hostTemplate: `{v1:[a-z]+}.google.com`, + shouldMatch: true, + }, + { + route: subrouter1.Path("/{v2:[a-z]+}"), + request: newRequest("GET", "http://111.google.com/111"), + vars: map[string]string{"v1": "aaa", "v2": "bbb"}, + host: "aaa.google.com", + path: "/bbb", + pathTemplate: `/{v2:[a-z]+}`, + hostTemplate: `{v1:[a-z]+}.google.com`, + shouldMatch: false, + }, + { + route: subrouter2.Path("/baz/{v2}"), + request: newRequest("GET", "http://localhost/foo/bar/baz/ding"), + vars: map[string]string{"v1": "bar", "v2": "ding"}, + host: "", + path: "/foo/bar/baz/ding", + pathTemplate: `/foo/{v1}/baz/{v2}`, + shouldMatch: true, + }, + { + route: subrouter2.Path("/baz/{v2}"), + request: newRequest("GET", "http://localhost/foo/bar"), + vars: map[string]string{"v1": "bar", "v2": "ding"}, + host: "", + path: "/foo/bar/baz/ding", + pathTemplate: `/foo/{v1}/baz/{v2}`, + shouldMatch: false, + }, + { + route: subrouter3.Path("/"), + request: newRequest("GET", "http://localhost/foo/"), + vars: map[string]string{}, + host: "", + path: "/foo/", + pathTemplate: `/foo/`, + shouldMatch: true, + }, + { + route: subrouter3.Path(""), + request: newRequest("GET", "http://localhost/foo"), + vars: map[string]string{}, + host: "", + path: "/foo", + pathTemplate: `/foo`, + shouldMatch: true, + }, + + { + route: subrouter4.Path("/"), + request: newRequest("GET", "http://localhost/foo/bar/"), + vars: map[string]string{}, + host: "", + path: "/foo/bar/", + pathTemplate: `/foo/bar/`, + shouldMatch: true, + }, + { + route: subrouter4.Path(""), + request: newRequest("GET", "http://localhost/foo/bar"), + vars: map[string]string{}, + host: "", + path: "/foo/bar", + pathTemplate: `/foo/bar`, + shouldMatch: true, + }, + { + route: subrouter5.Path("/"), + request: newRequest("GET", "http://localhost/baz/"), + vars: map[string]string{"category": "baz"}, + host: "", + path: "/baz/", + pathTemplate: `/{category}/`, + shouldMatch: true, + }, + { + route: subrouter5.Path(""), + request: newRequest("GET", "http://localhost/baz"), + vars: map[string]string{"category": "baz"}, + host: "", + path: "/baz", + pathTemplate: `/{category}`, + shouldMatch: true, + }, + } + + for _, test := range tests { + testRoute(t, test) + testTemplate(t, test) + testUseEscapedRoute(t, test) + } +} + +func TestNamedRoutes(t *testing.T) { + r1 := NewRouter() + r1.NewRoute().Name("a") + r1.NewRoute().Name("b") + r1.NewRoute().Name("c") + + r2 := r1.NewRoute().Subrouter() + r2.NewRoute().Name("d") + r2.NewRoute().Name("e") + r2.NewRoute().Name("f") + + r3 := r2.NewRoute().Subrouter() + r3.NewRoute().Name("g") + r3.NewRoute().Name("h") + r3.NewRoute().Name("i") + + if r1.namedRoutes == nil || len(r1.namedRoutes) != 9 { + t.Errorf("Expected 9 named routes, got %v", r1.namedRoutes) + } else if r1.Get("i") == nil { + t.Errorf("Subroute name not registered") + } +} + +func TestStrictSlash(t *testing.T) { + r := NewRouter() + r.StrictSlash(true) + + tests := []routeTest{ + { + title: "Redirect path without slash", + route: r.NewRoute().Path("/111/"), + request: newRequest("GET", "http://localhost/111"), + vars: map[string]string{}, + host: "", + path: "/111/", + shouldMatch: true, + shouldRedirect: true, + }, + { + title: "Do not redirect path with slash", + route: r.NewRoute().Path("/111/"), + request: newRequest("GET", "http://localhost/111/"), + vars: map[string]string{}, + host: "", + path: "/111/", + shouldMatch: true, + shouldRedirect: false, + }, + { + title: "Redirect path with slash", + route: r.NewRoute().Path("/111"), + request: newRequest("GET", "http://localhost/111/"), + vars: map[string]string{}, + host: "", + path: "/111", + shouldMatch: true, + shouldRedirect: true, + }, + { + title: "Do not redirect path without slash", + route: r.NewRoute().Path("/111"), + request: newRequest("GET", "http://localhost/111"), + vars: map[string]string{}, + host: "", + path: "/111", + shouldMatch: true, + shouldRedirect: false, + }, + { + title: "Propagate StrictSlash to subrouters", + route: r.NewRoute().PathPrefix("/static/").Subrouter().Path("/images/"), + request: newRequest("GET", "http://localhost/static/images"), + vars: map[string]string{}, + host: "", + path: "/static/images/", + shouldMatch: true, + shouldRedirect: true, + }, + { + title: "Ignore StrictSlash for path prefix", + route: r.NewRoute().PathPrefix("/static/"), + request: newRequest("GET", "http://localhost/static/logo.png"), + vars: map[string]string{}, + host: "", + path: "/static/", + shouldMatch: true, + shouldRedirect: false, + }, + } + + for _, test := range tests { + testRoute(t, test) + testTemplate(t, test) + testUseEscapedRoute(t, test) + } +} + +func TestUseEncodedPath(t *testing.T) { + r := NewRouter() + r.UseEncodedPath() + + tests := []routeTest{ + { + title: "Router with useEncodedPath, URL with encoded slash does match", + route: r.NewRoute().Path("/v1/{v1}/v2"), + request: newRequest("GET", "http://localhost/v1/1%2F2/v2"), + vars: map[string]string{"v1": "1%2F2"}, + host: "", + path: "/v1/1%2F2/v2", + pathTemplate: `/v1/{v1}/v2`, + shouldMatch: true, + }, + { + title: "Router with useEncodedPath, URL with encoded slash doesn't match", + route: r.NewRoute().Path("/v1/1/2/v2"), + request: newRequest("GET", "http://localhost/v1/1%2F2/v2"), + vars: map[string]string{"v1": "1%2F2"}, + host: "", + path: "/v1/1%2F2/v2", + pathTemplate: `/v1/1/2/v2`, + shouldMatch: false, + }, + } + + for _, test := range tests { + testRoute(t, test) + testTemplate(t, test) + } +} + +func TestWalkSingleDepth(t *testing.T) { + r0 := NewRouter() + r1 := NewRouter() + r2 := NewRouter() + + r0.Path("/g") + r0.Path("/o") + r0.Path("/d").Handler(r1) + r0.Path("/r").Handler(r2) + r0.Path("/a") + + r1.Path("/z") + r1.Path("/i") + r1.Path("/l") + r1.Path("/l") + + r2.Path("/i") + r2.Path("/l") + r2.Path("/l") + + paths := []string{"g", "o", "r", "i", "l", "l", "a"} + depths := []int{0, 0, 0, 1, 1, 1, 0} + i := 0 + err := r0.Walk(func(route *Route, router *Router, ancestors []*Route) error { + matcher := route.matchers[0].(*routeRegexp) + if matcher.template == "/d" { + return SkipRouter + } + if len(ancestors) != depths[i] { + t.Errorf(`Expected depth of %d at i = %d; got "%d"`, depths[i], i, len(ancestors)) + } + if matcher.template != "/"+paths[i] { + t.Errorf(`Expected "/%s" at i = %d; got "%s"`, paths[i], i, matcher.template) + } + i++ + return nil + }) + if err != nil { + panic(err) + } + if i != len(paths) { + t.Errorf("Expected %d routes, found %d", len(paths), i) + } +} + +func TestWalkNested(t *testing.T) { + router := NewRouter() + + g := router.Path("/g").Subrouter() + o := g.PathPrefix("/o").Subrouter() + r := o.PathPrefix("/r").Subrouter() + i := r.PathPrefix("/i").Subrouter() + l1 := i.PathPrefix("/l").Subrouter() + l2 := l1.PathPrefix("/l").Subrouter() + l2.Path("/a") + + paths := []string{"/g", "/g/o", "/g/o/r", "/g/o/r/i", "/g/o/r/i/l", "/g/o/r/i/l/l", "/g/o/r/i/l/l/a"} + idx := 0 + err := router.Walk(func(route *Route, router *Router, ancestors []*Route) error { + path := paths[idx] + tpl := route.regexp.path.template + if tpl != path { + t.Errorf(`Expected %s got %s`, path, tpl) + } + idx++ + return nil + }) + if err != nil { + panic(err) + } + if idx != len(paths) { + t.Errorf("Expected %d routes, found %d", len(paths), idx) + } +} + +func TestWalkErrorRoute(t *testing.T) { + router := NewRouter() + router.Path("/g") + expectedError := errors.New("error") + err := router.Walk(func(route *Route, router *Router, ancestors []*Route) error { + return expectedError + }) + if err != expectedError { + t.Errorf("Expected %v routes, found %v", expectedError, err) + } +} + +func TestWalkErrorMatcher(t *testing.T) { + router := NewRouter() + expectedError := router.Path("/g").Subrouter().Path("").GetError() + err := router.Walk(func(route *Route, router *Router, ancestors []*Route) error { + return route.GetError() + }) + if err != expectedError { + t.Errorf("Expected %v routes, found %v", expectedError, err) + } +} + +func TestWalkErrorHandler(t *testing.T) { + handler := NewRouter() + expectedError := handler.Path("/path").Subrouter().Path("").GetError() + router := NewRouter() + router.Path("/g").Handler(handler) + err := router.Walk(func(route *Route, router *Router, ancestors []*Route) error { + return route.GetError() + }) + if err != expectedError { + t.Errorf("Expected %v routes, found %v", expectedError, err) + } +} + +func TestSubrouterErrorHandling(t *testing.T) { + superRouterCalled := false + subRouterCalled := false + + router := NewRouter() + router.NotFoundHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + superRouterCalled = true + }) + subRouter := router.PathPrefix("/bign8").Subrouter() + subRouter.NotFoundHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + subRouterCalled = true + }) + + req, _ := http.NewRequest("GET", "http://localhost/bign8/was/here", nil) + router.ServeHTTP(NewRecorder(), req) + + if superRouterCalled { + t.Error("Super router 404 handler called when sub-router 404 handler is available.") + } + if !subRouterCalled { + t.Error("Sub-router 404 handler was not called.") + } +} + +// See: https://github.com/gorilla/mux/issues/200 +func TestPanicOnCapturingGroups(t *testing.T) { + defer func() { + if recover() == nil { + t.Errorf("(Test that capturing groups now fail fast) Expected panic, however test completed sucessfully.\n") + } + }() + NewRouter().NewRoute().Path("/{type:(promo|special)}/{promoId}.json") +} + +// ---------------------------------------------------------------------------- +// Helpers +// ---------------------------------------------------------------------------- + +func getRouteTemplate(route *Route) string { + host, err := route.GetHostTemplate() + if err != nil { + host = "none" + } + path, err := route.GetPathTemplate() + if err != nil { + path = "none" + } + return fmt.Sprintf("Host: %v, Path: %v", host, path) +} + +func testRoute(t *testing.T, test routeTest) { + request := test.request + route := test.route + vars := test.vars + shouldMatch := test.shouldMatch + host := test.host + path := test.path + url := test.host + test.path + shouldRedirect := test.shouldRedirect + + var match RouteMatch + ok := route.Match(request, &match) + if ok != shouldMatch { + msg := "Should match" + if !shouldMatch { + msg = "Should not match" + } + t.Errorf("(%v) %v:\nRoute: %#v\nRequest: %#v\nVars: %v\n", test.title, msg, route, request, vars) + return + } + if shouldMatch { + if test.vars != nil && !stringMapEqual(test.vars, match.Vars) { + t.Errorf("(%v) Vars not equal: expected %v, got %v", test.title, vars, match.Vars) + return + } + if host != "" { + u, _ := test.route.URLHost(mapToPairs(match.Vars)...) + if host != u.Host { + t.Errorf("(%v) URLHost not equal: expected %v, got %v -- %v", test.title, host, u.Host, getRouteTemplate(route)) + return + } + } + if path != "" { + u, _ := route.URLPath(mapToPairs(match.Vars)...) + if path != u.Path { + t.Errorf("(%v) URLPath not equal: expected %v, got %v -- %v", test.title, path, u.Path, getRouteTemplate(route)) + return + } + } + if url != "" { + u, _ := route.URL(mapToPairs(match.Vars)...) + if url != u.Host+u.Path { + t.Errorf("(%v) URL not equal: expected %v, got %v -- %v", test.title, url, u.Host+u.Path, getRouteTemplate(route)) + return + } + } + if shouldRedirect && match.Handler == nil { + t.Errorf("(%v) Did not redirect", test.title) + return + } + if !shouldRedirect && match.Handler != nil { + t.Errorf("(%v) Unexpected redirect", test.title) + return + } + } +} + +func testUseEscapedRoute(t *testing.T, test routeTest) { + test.route.useEncodedPath = true + testRoute(t, test) +} + +func testTemplate(t *testing.T, test routeTest) { + route := test.route + pathTemplate := test.pathTemplate + if len(pathTemplate) == 0 { + pathTemplate = test.path + } + hostTemplate := test.hostTemplate + if len(hostTemplate) == 0 { + hostTemplate = test.host + } + + routePathTemplate, pathErr := route.GetPathTemplate() + if pathErr == nil && routePathTemplate != pathTemplate { + t.Errorf("(%v) GetPathTemplate not equal: expected %v, got %v", test.title, pathTemplate, routePathTemplate) + } + + routeHostTemplate, hostErr := route.GetHostTemplate() + if hostErr == nil && routeHostTemplate != hostTemplate { + t.Errorf("(%v) GetHostTemplate not equal: expected %v, got %v", test.title, hostTemplate, routeHostTemplate) + } +} + +type TestA301ResponseWriter struct { + hh http.Header + status int +} + +func (ho TestA301ResponseWriter) Header() http.Header { + return http.Header(ho.hh) +} + +func (ho TestA301ResponseWriter) Write(b []byte) (int, error) { + return 0, nil +} + +func (ho TestA301ResponseWriter) WriteHeader(code int) { + ho.status = code +} + +func Test301Redirect(t *testing.T) { + m := make(http.Header) + + func1 := func(w http.ResponseWriter, r *http.Request) {} + func2 := func(w http.ResponseWriter, r *http.Request) {} + + r := NewRouter() + r.HandleFunc("/api/", func2).Name("func2") + r.HandleFunc("/", func1).Name("func1") + + req, _ := http.NewRequest("GET", "http://localhost//api/?abc=def", nil) + + res := TestA301ResponseWriter{ + hh: m, + status: 0, + } + r.ServeHTTP(&res, req) + + if "http://localhost/api/?abc=def" != res.hh["Location"][0] { + t.Errorf("Should have complete URL with query string") + } +} + +func TestSkipClean(t *testing.T) { + func1 := func(w http.ResponseWriter, r *http.Request) {} + func2 := func(w http.ResponseWriter, r *http.Request) {} + + r := NewRouter() + r.SkipClean(true) + r.HandleFunc("/api/", func2).Name("func2") + r.HandleFunc("/", func1).Name("func1") + + req, _ := http.NewRequest("GET", "http://localhost//api/?abc=def", nil) + res := NewRecorder() + r.ServeHTTP(res, req) + + if len(res.HeaderMap["Location"]) != 0 { + t.Errorf("Shouldn't redirect since skip clean is disabled") + } +} + +// https://plus.google.com/101022900381697718949/posts/eWy6DjFJ6uW +func TestSubrouterHeader(t *testing.T) { + expected := "func1 response" + func1 := func(w http.ResponseWriter, r *http.Request) { + fmt.Fprint(w, expected) + } + func2 := func(http.ResponseWriter, *http.Request) {} + + r := NewRouter() + s := r.Headers("SomeSpecialHeader", "").Subrouter() + s.HandleFunc("/", func1).Name("func1") + r.HandleFunc("/", func2).Name("func2") + + req, _ := http.NewRequest("GET", "http://localhost/", nil) + req.Header.Add("SomeSpecialHeader", "foo") + match := new(RouteMatch) + matched := r.Match(req, match) + if !matched { + t.Errorf("Should match request") + } + if match.Route.GetName() != "func1" { + t.Errorf("Expecting func1 handler, got %s", match.Route.GetName()) + } + resp := NewRecorder() + match.Handler.ServeHTTP(resp, req) + if resp.Body.String() != expected { + t.Errorf("Expecting %q", expected) + } +} + +// mapToPairs converts a string map to a slice of string pairs +func mapToPairs(m map[string]string) []string { + var i int + p := make([]string, len(m)*2) + for k, v := range m { + p[i] = k + p[i+1] = v + i += 2 + } + return p +} + +// stringMapEqual checks the equality of two string maps +func stringMapEqual(m1, m2 map[string]string) bool { + nil1 := m1 == nil + nil2 := m2 == nil + if nil1 != nil2 || len(m1) != len(m2) { + return false + } + for k, v := range m1 { + if v != m2[k] { + return false + } + } + return true +} + +// newRequest is a helper function to create a new request with a method and url. +// The request returned is a 'server' request as opposed to a 'client' one through +// simulated write onto the wire and read off of the wire. +// The differences between requests are detailed in the net/http package. +func newRequest(method, url string) *http.Request { + req, err := http.NewRequest(method, url, nil) + if err != nil { + panic(err) + } + // extract the escaped original host+path from url + // http://localhost/path/here?v=1#frag -> //localhost/path/here + opaque := "" + if i := len(req.URL.Scheme); i > 0 { + opaque = url[i+1:] + } + + if i := strings.LastIndex(opaque, "?"); i > -1 { + opaque = opaque[:i] + } + if i := strings.LastIndex(opaque, "#"); i > -1 { + opaque = opaque[:i] + } + + // Escaped host+path workaround as detailed in https://golang.org/pkg/net/url/#URL + // for < 1.5 client side workaround + req.URL.Opaque = opaque + + // Simulate writing to wire + var buff bytes.Buffer + req.Write(&buff) + ioreader := bufio.NewReader(&buff) + + // Parse request off of 'wire' + req, err = http.ReadRequest(ioreader) + if err != nil { + panic(err) + } + return req +} diff --git a/contrib/backends/nntpchand/src/vendor/github.com/gorilla/mux/old_test.go b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/mux/old_test.go new file mode 100644 index 0000000..9bdc5e5 --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/mux/old_test.go @@ -0,0 +1,710 @@ +// Old tests ported to Go1. This is a mess. Want to drop it one day. + +// Copyright 2011 Gorilla 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 mux + +import ( + "bytes" + "net/http" + "testing" +) + +// ---------------------------------------------------------------------------- +// ResponseRecorder +// ---------------------------------------------------------------------------- +// Copyright 2009 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. + +// ResponseRecorder is an implementation of http.ResponseWriter that +// records its mutations for later inspection in tests. +type ResponseRecorder struct { + Code int // the HTTP response code from WriteHeader + HeaderMap http.Header // the HTTP response headers + Body *bytes.Buffer // if non-nil, the bytes.Buffer to append written data to + Flushed bool +} + +// NewRecorder returns an initialized ResponseRecorder. +func NewRecorder() *ResponseRecorder { + return &ResponseRecorder{ + HeaderMap: make(http.Header), + Body: new(bytes.Buffer), + } +} + +// Header returns the response headers. +func (rw *ResponseRecorder) Header() http.Header { + return rw.HeaderMap +} + +// Write always succeeds and writes to rw.Body, if not nil. +func (rw *ResponseRecorder) Write(buf []byte) (int, error) { + if rw.Body != nil { + rw.Body.Write(buf) + } + if rw.Code == 0 { + rw.Code = http.StatusOK + } + return len(buf), nil +} + +// WriteHeader sets rw.Code. +func (rw *ResponseRecorder) WriteHeader(code int) { + rw.Code = code +} + +// Flush sets rw.Flushed to true. +func (rw *ResponseRecorder) Flush() { + rw.Flushed = true +} + +// ---------------------------------------------------------------------------- + +func TestRouteMatchers(t *testing.T) { + var scheme, host, path, query, method string + var headers map[string]string + var resultVars map[bool]map[string]string + + router := NewRouter() + router.NewRoute().Host("{var1}.google.com"). + Path("/{var2:[a-z]+}/{var3:[0-9]+}"). + Queries("foo", "bar"). + Methods("GET"). + Schemes("https"). + Headers("x-requested-with", "XMLHttpRequest") + router.NewRoute().Host("www.{var4}.com"). + PathPrefix("/foo/{var5:[a-z]+}/{var6:[0-9]+}"). + Queries("baz", "ding"). + Methods("POST"). + Schemes("http"). + Headers("Content-Type", "application/json") + + reset := func() { + // Everything match. + scheme = "https" + host = "www.google.com" + path = "/product/42" + query = "?foo=bar" + method = "GET" + headers = map[string]string{"X-Requested-With": "XMLHttpRequest"} + resultVars = map[bool]map[string]string{ + true: {"var1": "www", "var2": "product", "var3": "42"}, + false: {}, + } + } + + reset2 := func() { + // Everything match. + scheme = "http" + host = "www.google.com" + path = "/foo/product/42/path/that/is/ignored" + query = "?baz=ding" + method = "POST" + headers = map[string]string{"Content-Type": "application/json"} + resultVars = map[bool]map[string]string{ + true: {"var4": "google", "var5": "product", "var6": "42"}, + false: {}, + } + } + + match := func(shouldMatch bool) { + url := scheme + "://" + host + path + query + request, _ := http.NewRequest(method, url, nil) + for key, value := range headers { + request.Header.Add(key, value) + } + + var routeMatch RouteMatch + matched := router.Match(request, &routeMatch) + if matched != shouldMatch { + // Need better messages. :) + if matched { + t.Errorf("Should match.") + } else { + t.Errorf("Should not match.") + } + } + + if matched { + currentRoute := routeMatch.Route + if currentRoute == nil { + t.Errorf("Expected a current route.") + } + vars := routeMatch.Vars + expectedVars := resultVars[shouldMatch] + if len(vars) != len(expectedVars) { + t.Errorf("Expected vars: %v Got: %v.", expectedVars, vars) + } + for name, value := range vars { + if expectedVars[name] != value { + t.Errorf("Expected vars: %v Got: %v.", expectedVars, vars) + } + } + } + } + + // 1st route -------------------------------------------------------------- + + // Everything match. + reset() + match(true) + + // Scheme doesn't match. + reset() + scheme = "http" + match(false) + + // Host doesn't match. + reset() + host = "www.mygoogle.com" + match(false) + + // Path doesn't match. + reset() + path = "/product/notdigits" + match(false) + + // Query doesn't match. + reset() + query = "?foo=baz" + match(false) + + // Method doesn't match. + reset() + method = "POST" + match(false) + + // Header doesn't match. + reset() + headers = map[string]string{} + match(false) + + // Everything match, again. + reset() + match(true) + + // 2nd route -------------------------------------------------------------- + + // Everything match. + reset2() + match(true) + + // Scheme doesn't match. + reset2() + scheme = "https" + match(false) + + // Host doesn't match. + reset2() + host = "sub.google.com" + match(false) + + // Path doesn't match. + reset2() + path = "/bar/product/42" + match(false) + + // Query doesn't match. + reset2() + query = "?foo=baz" + match(false) + + // Method doesn't match. + reset2() + method = "GET" + match(false) + + // Header doesn't match. + reset2() + headers = map[string]string{} + match(false) + + // Everything match, again. + reset2() + match(true) +} + +type headerMatcherTest struct { + matcher headerMatcher + headers map[string]string + result bool +} + +var headerMatcherTests = []headerMatcherTest{ + { + matcher: headerMatcher(map[string]string{"x-requested-with": "XMLHttpRequest"}), + headers: map[string]string{"X-Requested-With": "XMLHttpRequest"}, + result: true, + }, + { + matcher: headerMatcher(map[string]string{"x-requested-with": ""}), + headers: map[string]string{"X-Requested-With": "anything"}, + result: true, + }, + { + matcher: headerMatcher(map[string]string{"x-requested-with": "XMLHttpRequest"}), + headers: map[string]string{}, + result: false, + }, +} + +type hostMatcherTest struct { + matcher *Route + url string + vars map[string]string + result bool +} + +var hostMatcherTests = []hostMatcherTest{ + { + matcher: NewRouter().NewRoute().Host("{foo:[a-z][a-z][a-z]}.{bar:[a-z][a-z][a-z]}.{baz:[a-z][a-z][a-z]}"), + url: "http://abc.def.ghi/", + vars: map[string]string{"foo": "abc", "bar": "def", "baz": "ghi"}, + result: true, + }, + { + matcher: NewRouter().NewRoute().Host("{foo:[a-z][a-z][a-z]}.{bar:[a-z][a-z][a-z]}.{baz:[a-z][a-z][a-z]}"), + url: "http://a.b.c/", + vars: map[string]string{"foo": "abc", "bar": "def", "baz": "ghi"}, + result: false, + }, +} + +type methodMatcherTest struct { + matcher methodMatcher + method string + result bool +} + +var methodMatcherTests = []methodMatcherTest{ + { + matcher: methodMatcher([]string{"GET", "POST", "PUT"}), + method: "GET", + result: true, + }, + { + matcher: methodMatcher([]string{"GET", "POST", "PUT"}), + method: "POST", + result: true, + }, + { + matcher: methodMatcher([]string{"GET", "POST", "PUT"}), + method: "PUT", + result: true, + }, + { + matcher: methodMatcher([]string{"GET", "POST", "PUT"}), + method: "DELETE", + result: false, + }, +} + +type pathMatcherTest struct { + matcher *Route + url string + vars map[string]string + result bool +} + +var pathMatcherTests = []pathMatcherTest{ + { + matcher: NewRouter().NewRoute().Path("/{foo:[0-9][0-9][0-9]}/{bar:[0-9][0-9][0-9]}/{baz:[0-9][0-9][0-9]}"), + url: "http://localhost:8080/123/456/789", + vars: map[string]string{"foo": "123", "bar": "456", "baz": "789"}, + result: true, + }, + { + matcher: NewRouter().NewRoute().Path("/{foo:[0-9][0-9][0-9]}/{bar:[0-9][0-9][0-9]}/{baz:[0-9][0-9][0-9]}"), + url: "http://localhost:8080/1/2/3", + vars: map[string]string{"foo": "123", "bar": "456", "baz": "789"}, + result: false, + }, +} + +type schemeMatcherTest struct { + matcher schemeMatcher + url string + result bool +} + +var schemeMatcherTests = []schemeMatcherTest{ + { + matcher: schemeMatcher([]string{"http", "https"}), + url: "http://localhost:8080/", + result: true, + }, + { + matcher: schemeMatcher([]string{"http", "https"}), + url: "https://localhost:8080/", + result: true, + }, + { + matcher: schemeMatcher([]string{"https"}), + url: "http://localhost:8080/", + result: false, + }, + { + matcher: schemeMatcher([]string{"http"}), + url: "https://localhost:8080/", + result: false, + }, +} + +type urlBuildingTest struct { + route *Route + vars []string + url string +} + +var urlBuildingTests = []urlBuildingTest{ + { + route: new(Route).Host("foo.domain.com"), + vars: []string{}, + url: "http://foo.domain.com", + }, + { + route: new(Route).Host("{subdomain}.domain.com"), + vars: []string{"subdomain", "bar"}, + url: "http://bar.domain.com", + }, + { + route: new(Route).Host("foo.domain.com").Path("/articles"), + vars: []string{}, + url: "http://foo.domain.com/articles", + }, + { + route: new(Route).Path("/articles"), + vars: []string{}, + url: "/articles", + }, + { + route: new(Route).Path("/articles/{category}/{id:[0-9]+}"), + vars: []string{"category", "technology", "id", "42"}, + url: "/articles/technology/42", + }, + { + route: new(Route).Host("{subdomain}.domain.com").Path("/articles/{category}/{id:[0-9]+}"), + vars: []string{"subdomain", "foo", "category", "technology", "id", "42"}, + url: "http://foo.domain.com/articles/technology/42", + }, +} + +func TestHeaderMatcher(t *testing.T) { + for _, v := range headerMatcherTests { + request, _ := http.NewRequest("GET", "http://localhost:8080/", nil) + for key, value := range v.headers { + request.Header.Add(key, value) + } + var routeMatch RouteMatch + result := v.matcher.Match(request, &routeMatch) + if result != v.result { + if v.result { + t.Errorf("%#v: should match %v.", v.matcher, request.Header) + } else { + t.Errorf("%#v: should not match %v.", v.matcher, request.Header) + } + } + } +} + +func TestHostMatcher(t *testing.T) { + for _, v := range hostMatcherTests { + request, _ := http.NewRequest("GET", v.url, nil) + var routeMatch RouteMatch + result := v.matcher.Match(request, &routeMatch) + vars := routeMatch.Vars + if result != v.result { + if v.result { + t.Errorf("%#v: should match %v.", v.matcher, v.url) + } else { + t.Errorf("%#v: should not match %v.", v.matcher, v.url) + } + } + if result { + if len(vars) != len(v.vars) { + t.Errorf("%#v: vars length should be %v, got %v.", v.matcher, len(v.vars), len(vars)) + } + for name, value := range vars { + if v.vars[name] != value { + t.Errorf("%#v: expected value %v for key %v, got %v.", v.matcher, v.vars[name], name, value) + } + } + } else { + if len(vars) != 0 { + t.Errorf("%#v: vars length should be 0, got %v.", v.matcher, len(vars)) + } + } + } +} + +func TestMethodMatcher(t *testing.T) { + for _, v := range methodMatcherTests { + request, _ := http.NewRequest(v.method, "http://localhost:8080/", nil) + var routeMatch RouteMatch + result := v.matcher.Match(request, &routeMatch) + if result != v.result { + if v.result { + t.Errorf("%#v: should match %v.", v.matcher, v.method) + } else { + t.Errorf("%#v: should not match %v.", v.matcher, v.method) + } + } + } +} + +func TestPathMatcher(t *testing.T) { + for _, v := range pathMatcherTests { + request, _ := http.NewRequest("GET", v.url, nil) + var routeMatch RouteMatch + result := v.matcher.Match(request, &routeMatch) + vars := routeMatch.Vars + if result != v.result { + if v.result { + t.Errorf("%#v: should match %v.", v.matcher, v.url) + } else { + t.Errorf("%#v: should not match %v.", v.matcher, v.url) + } + } + if result { + if len(vars) != len(v.vars) { + t.Errorf("%#v: vars length should be %v, got %v.", v.matcher, len(v.vars), len(vars)) + } + for name, value := range vars { + if v.vars[name] != value { + t.Errorf("%#v: expected value %v for key %v, got %v.", v.matcher, v.vars[name], name, value) + } + } + } else { + if len(vars) != 0 { + t.Errorf("%#v: vars length should be 0, got %v.", v.matcher, len(vars)) + } + } + } +} + +func TestSchemeMatcher(t *testing.T) { + for _, v := range schemeMatcherTests { + request, _ := http.NewRequest("GET", v.url, nil) + var routeMatch RouteMatch + result := v.matcher.Match(request, &routeMatch) + if result != v.result { + if v.result { + t.Errorf("%#v: should match %v.", v.matcher, v.url) + } else { + t.Errorf("%#v: should not match %v.", v.matcher, v.url) + } + } + } +} + +func TestUrlBuilding(t *testing.T) { + + for _, v := range urlBuildingTests { + u, _ := v.route.URL(v.vars...) + url := u.String() + if url != v.url { + t.Errorf("expected %v, got %v", v.url, url) + /* + reversePath := "" + reverseHost := "" + if v.route.pathTemplate != nil { + reversePath = v.route.pathTemplate.Reverse + } + if v.route.hostTemplate != nil { + reverseHost = v.route.hostTemplate.Reverse + } + + t.Errorf("%#v:\nexpected: %q\ngot: %q\nreverse path: %q\nreverse host: %q", v.route, v.url, url, reversePath, reverseHost) + */ + } + } + + ArticleHandler := func(w http.ResponseWriter, r *http.Request) { + } + + router := NewRouter() + router.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler).Name("article") + + url, _ := router.Get("article").URL("category", "technology", "id", "42") + expected := "/articles/technology/42" + if url.String() != expected { + t.Errorf("Expected %v, got %v", expected, url.String()) + } +} + +func TestMatchedRouteName(t *testing.T) { + routeName := "stock" + router := NewRouter() + route := router.NewRoute().Path("/products/").Name(routeName) + + url := "http://www.example.com/products/" + request, _ := http.NewRequest("GET", url, nil) + var rv RouteMatch + ok := router.Match(request, &rv) + + if !ok || rv.Route != route { + t.Errorf("Expected same route, got %+v.", rv.Route) + } + + retName := rv.Route.GetName() + if retName != routeName { + t.Errorf("Expected %q, got %q.", routeName, retName) + } +} + +func TestSubRouting(t *testing.T) { + // Example from docs. + router := NewRouter() + subrouter := router.NewRoute().Host("www.example.com").Subrouter() + route := subrouter.NewRoute().Path("/products/").Name("products") + + url := "http://www.example.com/products/" + request, _ := http.NewRequest("GET", url, nil) + var rv RouteMatch + ok := router.Match(request, &rv) + + if !ok || rv.Route != route { + t.Errorf("Expected same route, got %+v.", rv.Route) + } + + u, _ := router.Get("products").URL() + builtURL := u.String() + // Yay, subroute aware of the domain when building! + if builtURL != url { + t.Errorf("Expected %q, got %q.", url, builtURL) + } +} + +func TestVariableNames(t *testing.T) { + route := new(Route).Host("{arg1}.domain.com").Path("/{arg1}/{arg2:[0-9]+}") + if route.err == nil { + t.Errorf("Expected error for duplicated variable names") + } +} + +func TestRedirectSlash(t *testing.T) { + var route *Route + var routeMatch RouteMatch + r := NewRouter() + + r.StrictSlash(false) + route = r.NewRoute() + if route.strictSlash != false { + t.Errorf("Expected false redirectSlash.") + } + + r.StrictSlash(true) + route = r.NewRoute() + if route.strictSlash != true { + t.Errorf("Expected true redirectSlash.") + } + + route = new(Route) + route.strictSlash = true + route.Path("/{arg1}/{arg2:[0-9]+}/") + request, _ := http.NewRequest("GET", "http://localhost/foo/123", nil) + routeMatch = RouteMatch{} + _ = route.Match(request, &routeMatch) + vars := routeMatch.Vars + if vars["arg1"] != "foo" { + t.Errorf("Expected foo.") + } + if vars["arg2"] != "123" { + t.Errorf("Expected 123.") + } + rsp := NewRecorder() + routeMatch.Handler.ServeHTTP(rsp, request) + if rsp.HeaderMap.Get("Location") != "http://localhost/foo/123/" { + t.Errorf("Expected redirect header.") + } + + route = new(Route) + route.strictSlash = true + route.Path("/{arg1}/{arg2:[0-9]+}") + request, _ = http.NewRequest("GET", "http://localhost/foo/123/", nil) + routeMatch = RouteMatch{} + _ = route.Match(request, &routeMatch) + vars = routeMatch.Vars + if vars["arg1"] != "foo" { + t.Errorf("Expected foo.") + } + if vars["arg2"] != "123" { + t.Errorf("Expected 123.") + } + rsp = NewRecorder() + routeMatch.Handler.ServeHTTP(rsp, request) + if rsp.HeaderMap.Get("Location") != "http://localhost/foo/123" { + t.Errorf("Expected redirect header.") + } +} + +// Test for the new regexp library, still not available in stable Go. +func TestNewRegexp(t *testing.T) { + var p *routeRegexp + var matches []string + + tests := map[string]map[string][]string{ + "/{foo:a{2}}": { + "/a": nil, + "/aa": {"aa"}, + "/aaa": nil, + "/aaaa": nil, + }, + "/{foo:a{2,}}": { + "/a": nil, + "/aa": {"aa"}, + "/aaa": {"aaa"}, + "/aaaa": {"aaaa"}, + }, + "/{foo:a{2,3}}": { + "/a": nil, + "/aa": {"aa"}, + "/aaa": {"aaa"}, + "/aaaa": nil, + }, + "/{foo:[a-z]{3}}/{bar:[a-z]{2}}": { + "/a": nil, + "/ab": nil, + "/abc": nil, + "/abcd": nil, + "/abc/ab": {"abc", "ab"}, + "/abc/abc": nil, + "/abcd/ab": nil, + }, + `/{foo:\w{3,}}/{bar:\d{2,}}`: { + "/a": nil, + "/ab": nil, + "/abc": nil, + "/abc/1": nil, + "/abc/12": {"abc", "12"}, + "/abcd/12": {"abcd", "12"}, + "/abcd/123": {"abcd", "123"}, + }, + } + + for pattern, paths := range tests { + p, _ = newRouteRegexp(pattern, false, false, false, false, false) + for path, result := range paths { + matches = p.regexp.FindStringSubmatch(path) + if result == nil { + if matches != nil { + t.Errorf("%v should not match %v.", pattern, path) + } + } else { + if len(matches) != len(result)+1 { + t.Errorf("Expected %v matches, got %v.", len(result)+1, len(matches)) + } else { + for k, v := range result { + if matches[k+1] != v { + t.Errorf("Expected %v, got %v.", v, matches[k+1]) + } + } + } + } + } + } +} diff --git a/contrib/backends/nntpchand/src/vendor/github.com/gorilla/mux/regexp.go b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/mux/regexp.go new file mode 100644 index 0000000..0189ad3 --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/mux/regexp.go @@ -0,0 +1,323 @@ +// Copyright 2012 The Gorilla 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 mux + +import ( + "bytes" + "fmt" + "net/http" + "net/url" + "regexp" + "strconv" + "strings" +) + +// newRouteRegexp parses a route template and returns a routeRegexp, +// used to match a host, a path or a query string. +// +// It will extract named variables, assemble a regexp to be matched, create +// a "reverse" template to build URLs and compile regexps to validate variable +// values used in URL building. +// +// Previously we accepted only Python-like identifiers for variable +// names ([a-zA-Z_][a-zA-Z0-9_]*), but currently the only restriction is that +// name and pattern can't be empty, and names can't contain a colon. +func newRouteRegexp(tpl string, matchHost, matchPrefix, matchQuery, strictSlash, useEncodedPath bool) (*routeRegexp, error) { + // Check if it is well-formed. + idxs, errBraces := braceIndices(tpl) + if errBraces != nil { + return nil, errBraces + } + // Backup the original. + template := tpl + // Now let's parse it. + defaultPattern := "[^/]+" + if matchQuery { + defaultPattern = "[^?&]*" + } else if matchHost { + defaultPattern = "[^.]+" + matchPrefix = false + } + // Only match strict slash if not matching + if matchPrefix || matchHost || matchQuery { + strictSlash = false + } + // Set a flag for strictSlash. + endSlash := false + if strictSlash && strings.HasSuffix(tpl, "/") { + tpl = tpl[:len(tpl)-1] + endSlash = true + } + varsN := make([]string, len(idxs)/2) + varsR := make([]*regexp.Regexp, len(idxs)/2) + pattern := bytes.NewBufferString("") + pattern.WriteByte('^') + reverse := bytes.NewBufferString("") + var end int + var err error + for i := 0; i < len(idxs); i += 2 { + // Set all values we are interested in. + raw := tpl[end:idxs[i]] + end = idxs[i+1] + parts := strings.SplitN(tpl[idxs[i]+1:end-1], ":", 2) + name := parts[0] + patt := defaultPattern + if len(parts) == 2 { + patt = parts[1] + } + // Name or pattern can't be empty. + if name == "" || patt == "" { + return nil, fmt.Errorf("mux: missing name or pattern in %q", + tpl[idxs[i]:end]) + } + // Build the regexp pattern. + fmt.Fprintf(pattern, "%s(?P<%s>%s)", regexp.QuoteMeta(raw), varGroupName(i/2), patt) + + // Build the reverse template. + fmt.Fprintf(reverse, "%s%%s", raw) + + // Append variable name and compiled pattern. + varsN[i/2] = name + varsR[i/2], err = regexp.Compile(fmt.Sprintf("^%s$", patt)) + if err != nil { + return nil, err + } + } + // Add the remaining. + raw := tpl[end:] + pattern.WriteString(regexp.QuoteMeta(raw)) + if strictSlash { + pattern.WriteString("[/]?") + } + if matchQuery { + // Add the default pattern if the query value is empty + if queryVal := strings.SplitN(template, "=", 2)[1]; queryVal == "" { + pattern.WriteString(defaultPattern) + } + } + if !matchPrefix { + pattern.WriteByte('$') + } + reverse.WriteString(raw) + if endSlash { + reverse.WriteByte('/') + } + // Compile full regexp. + reg, errCompile := regexp.Compile(pattern.String()) + if errCompile != nil { + return nil, errCompile + } + + // Check for capturing groups which used to work in older versions + if reg.NumSubexp() != len(idxs)/2 { + panic(fmt.Sprintf("route %s contains capture groups in its regexp. ", template) + + "Only non-capturing groups are accepted: e.g. (?:pattern) instead of (pattern)") + } + + // Done! + return &routeRegexp{ + template: template, + matchHost: matchHost, + matchQuery: matchQuery, + strictSlash: strictSlash, + useEncodedPath: useEncodedPath, + regexp: reg, + reverse: reverse.String(), + varsN: varsN, + varsR: varsR, + }, nil +} + +// routeRegexp stores a regexp to match a host or path and information to +// collect and validate route variables. +type routeRegexp struct { + // The unmodified template. + template string + // True for host match, false for path or query string match. + matchHost bool + // True for query string match, false for path and host match. + matchQuery bool + // The strictSlash value defined on the route, but disabled if PathPrefix was used. + strictSlash bool + // Determines whether to use encoded path from getPath function or unencoded + // req.URL.Path for path matching + useEncodedPath bool + // Expanded regexp. + regexp *regexp.Regexp + // Reverse template. + reverse string + // Variable names. + varsN []string + // Variable regexps (validators). + varsR []*regexp.Regexp +} + +// Match matches the regexp against the URL host or path. +func (r *routeRegexp) Match(req *http.Request, match *RouteMatch) bool { + if !r.matchHost { + if r.matchQuery { + return r.matchQueryString(req) + } + path := req.URL.Path + if r.useEncodedPath { + path = getPath(req) + } + return r.regexp.MatchString(path) + } + + return r.regexp.MatchString(getHost(req)) +} + +// url builds a URL part using the given values. +func (r *routeRegexp) url(values map[string]string) (string, error) { + urlValues := make([]interface{}, len(r.varsN)) + for k, v := range r.varsN { + value, ok := values[v] + if !ok { + return "", fmt.Errorf("mux: missing route variable %q", v) + } + urlValues[k] = value + } + rv := fmt.Sprintf(r.reverse, urlValues...) + if !r.regexp.MatchString(rv) { + // The URL is checked against the full regexp, instead of checking + // individual variables. This is faster but to provide a good error + // message, we check individual regexps if the URL doesn't match. + for k, v := range r.varsN { + if !r.varsR[k].MatchString(values[v]) { + return "", fmt.Errorf( + "mux: variable %q doesn't match, expected %q", values[v], + r.varsR[k].String()) + } + } + } + return rv, nil +} + +// getURLQuery returns a single query parameter from a request URL. +// For a URL with foo=bar&baz=ding, we return only the relevant key +// value pair for the routeRegexp. +func (r *routeRegexp) getURLQuery(req *http.Request) string { + if !r.matchQuery { + return "" + } + templateKey := strings.SplitN(r.template, "=", 2)[0] + for key, vals := range req.URL.Query() { + if key == templateKey && len(vals) > 0 { + return key + "=" + vals[0] + } + } + return "" +} + +func (r *routeRegexp) matchQueryString(req *http.Request) bool { + return r.regexp.MatchString(r.getURLQuery(req)) +} + +// braceIndices returns the first level curly brace indices from a string. +// It returns an error in case of unbalanced braces. +func braceIndices(s string) ([]int, error) { + var level, idx int + var idxs []int + for i := 0; i < len(s); i++ { + switch s[i] { + case '{': + if level++; level == 1 { + idx = i + } + case '}': + if level--; level == 0 { + idxs = append(idxs, idx, i+1) + } else if level < 0 { + return nil, fmt.Errorf("mux: unbalanced braces in %q", s) + } + } + } + if level != 0 { + return nil, fmt.Errorf("mux: unbalanced braces in %q", s) + } + return idxs, nil +} + +// varGroupName builds a capturing group name for the indexed variable. +func varGroupName(idx int) string { + return "v" + strconv.Itoa(idx) +} + +// ---------------------------------------------------------------------------- +// routeRegexpGroup +// ---------------------------------------------------------------------------- + +// routeRegexpGroup groups the route matchers that carry variables. +type routeRegexpGroup struct { + host *routeRegexp + path *routeRegexp + queries []*routeRegexp +} + +// setMatch extracts the variables from the URL once a route matches. +func (v *routeRegexpGroup) setMatch(req *http.Request, m *RouteMatch, r *Route) { + // Store host variables. + if v.host != nil { + host := getHost(req) + matches := v.host.regexp.FindStringSubmatchIndex(host) + if len(matches) > 0 { + extractVars(host, matches, v.host.varsN, m.Vars) + } + } + path := req.URL.Path + if r.useEncodedPath { + path = getPath(req) + } + // Store path variables. + if v.path != nil { + matches := v.path.regexp.FindStringSubmatchIndex(path) + if len(matches) > 0 { + extractVars(path, matches, v.path.varsN, m.Vars) + // Check if we should redirect. + if v.path.strictSlash { + p1 := strings.HasSuffix(path, "/") + p2 := strings.HasSuffix(v.path.template, "/") + if p1 != p2 { + u, _ := url.Parse(req.URL.String()) + if p1 { + u.Path = u.Path[:len(u.Path)-1] + } else { + u.Path += "/" + } + m.Handler = http.RedirectHandler(u.String(), 301) + } + } + } + } + // Store query string variables. + for _, q := range v.queries { + queryURL := q.getURLQuery(req) + matches := q.regexp.FindStringSubmatchIndex(queryURL) + if len(matches) > 0 { + extractVars(queryURL, matches, q.varsN, m.Vars) + } + } +} + +// getHost tries its best to return the request host. +func getHost(r *http.Request) string { + if r.URL.IsAbs() { + return r.URL.Host + } + host := r.Host + // Slice off any port information. + if i := strings.Index(host, ":"); i != -1 { + host = host[:i] + } + return host + +} + +func extractVars(input string, matches []int, names []string, output map[string]string) { + for i, name := range names { + output[name] = input[matches[2*i+2]:matches[2*i+3]] + } +} diff --git a/contrib/backends/nntpchand/src/vendor/github.com/gorilla/mux/route.go b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/mux/route.go new file mode 100644 index 0000000..5544c1f --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/mux/route.go @@ -0,0 +1,636 @@ +// Copyright 2012 The Gorilla 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 mux + +import ( + "errors" + "fmt" + "net/http" + "net/url" + "regexp" + "strings" +) + +// Route stores information to match a request and build URLs. +type Route struct { + // Parent where the route was registered (a Router). + parent parentRoute + // Request handler for the route. + handler http.Handler + // List of matchers. + matchers []matcher + // Manager for the variables from host and path. + regexp *routeRegexpGroup + // If true, when the path pattern is "/path/", accessing "/path" will + // redirect to the former and vice versa. + strictSlash bool + // If true, when the path pattern is "/path//to", accessing "/path//to" + // will not redirect + skipClean bool + // If true, "/path/foo%2Fbar/to" will match the path "/path/{var}/to" + useEncodedPath bool + // If true, this route never matches: it is only used to build URLs. + buildOnly bool + // The name used to build URLs. + name string + // Error resulted from building a route. + err error + + buildVarsFunc BuildVarsFunc +} + +func (r *Route) SkipClean() bool { + return r.skipClean +} + +// Match matches the route against the request. +func (r *Route) Match(req *http.Request, match *RouteMatch) bool { + if r.buildOnly || r.err != nil { + return false + } + // Match everything. + for _, m := range r.matchers { + if matched := m.Match(req, match); !matched { + return false + } + } + // Yay, we have a match. Let's collect some info about it. + if match.Route == nil { + match.Route = r + } + if match.Handler == nil { + match.Handler = r.handler + } + if match.Vars == nil { + match.Vars = make(map[string]string) + } + // Set variables. + if r.regexp != nil { + r.regexp.setMatch(req, match, r) + } + return true +} + +// ---------------------------------------------------------------------------- +// Route attributes +// ---------------------------------------------------------------------------- + +// GetError returns an error resulted from building the route, if any. +func (r *Route) GetError() error { + return r.err +} + +// BuildOnly sets the route to never match: it is only used to build URLs. +func (r *Route) BuildOnly() *Route { + r.buildOnly = true + return r +} + +// Handler -------------------------------------------------------------------- + +// Handler sets a handler for the route. +func (r *Route) Handler(handler http.Handler) *Route { + if r.err == nil { + r.handler = handler + } + return r +} + +// HandlerFunc sets a handler function for the route. +func (r *Route) HandlerFunc(f func(http.ResponseWriter, *http.Request)) *Route { + return r.Handler(http.HandlerFunc(f)) +} + +// GetHandler returns the handler for the route, if any. +func (r *Route) GetHandler() http.Handler { + return r.handler +} + +// Name ----------------------------------------------------------------------- + +// Name sets the name for the route, used to build URLs. +// If the name was registered already it will be overwritten. +func (r *Route) Name(name string) *Route { + if r.name != "" { + r.err = fmt.Errorf("mux: route already has name %q, can't set %q", + r.name, name) + } + if r.err == nil { + r.name = name + r.getNamedRoutes()[name] = r + } + return r +} + +// GetName returns the name for the route, if any. +func (r *Route) GetName() string { + return r.name +} + +// ---------------------------------------------------------------------------- +// Matchers +// ---------------------------------------------------------------------------- + +// matcher types try to match a request. +type matcher interface { + Match(*http.Request, *RouteMatch) bool +} + +// addMatcher adds a matcher to the route. +func (r *Route) addMatcher(m matcher) *Route { + if r.err == nil { + r.matchers = append(r.matchers, m) + } + return r +} + +// addRegexpMatcher adds a host or path matcher and builder to a route. +func (r *Route) addRegexpMatcher(tpl string, matchHost, matchPrefix, matchQuery bool) error { + if r.err != nil { + return r.err + } + r.regexp = r.getRegexpGroup() + if !matchHost && !matchQuery { + if len(tpl) > 0 && tpl[0] != '/' { + return fmt.Errorf("mux: path must start with a slash, got %q", tpl) + } + if r.regexp.path != nil { + tpl = strings.TrimRight(r.regexp.path.template, "/") + tpl + } + } + rr, err := newRouteRegexp(tpl, matchHost, matchPrefix, matchQuery, r.strictSlash, r.useEncodedPath) + if err != nil { + return err + } + for _, q := range r.regexp.queries { + if err = uniqueVars(rr.varsN, q.varsN); err != nil { + return err + } + } + if matchHost { + if r.regexp.path != nil { + if err = uniqueVars(rr.varsN, r.regexp.path.varsN); err != nil { + return err + } + } + r.regexp.host = rr + } else { + if r.regexp.host != nil { + if err = uniqueVars(rr.varsN, r.regexp.host.varsN); err != nil { + return err + } + } + if matchQuery { + r.regexp.queries = append(r.regexp.queries, rr) + } else { + r.regexp.path = rr + } + } + r.addMatcher(rr) + return nil +} + +// Headers -------------------------------------------------------------------- + +// headerMatcher matches the request against header values. +type headerMatcher map[string]string + +func (m headerMatcher) Match(r *http.Request, match *RouteMatch) bool { + return matchMapWithString(m, r.Header, true) +} + +// Headers adds a matcher for request header values. +// It accepts a sequence of key/value pairs to be matched. For example: +// +// r := mux.NewRouter() +// r.Headers("Content-Type", "application/json", +// "X-Requested-With", "XMLHttpRequest") +// +// The above route will only match if both request header values match. +// If the value is an empty string, it will match any value if the key is set. +func (r *Route) Headers(pairs ...string) *Route { + if r.err == nil { + var headers map[string]string + headers, r.err = mapFromPairsToString(pairs...) + return r.addMatcher(headerMatcher(headers)) + } + return r +} + +// headerRegexMatcher matches the request against the route given a regex for the header +type headerRegexMatcher map[string]*regexp.Regexp + +func (m headerRegexMatcher) Match(r *http.Request, match *RouteMatch) bool { + return matchMapWithRegex(m, r.Header, true) +} + +// HeadersRegexp accepts a sequence of key/value pairs, where the value has regex +// support. For example: +// +// r := mux.NewRouter() +// r.HeadersRegexp("Content-Type", "application/(text|json)", +// "X-Requested-With", "XMLHttpRequest") +// +// The above route will only match if both the request header matches both regular expressions. +// It the value is an empty string, it will match any value if the key is set. +func (r *Route) HeadersRegexp(pairs ...string) *Route { + if r.err == nil { + var headers map[string]*regexp.Regexp + headers, r.err = mapFromPairsToRegex(pairs...) + return r.addMatcher(headerRegexMatcher(headers)) + } + return r +} + +// Host ----------------------------------------------------------------------- + +// Host adds a matcher for the URL host. +// It accepts a template with zero or more URL variables enclosed by {}. +// Variables can define an optional regexp pattern to be matched: +// +// - {name} matches anything until the next dot. +// +// - {name:pattern} matches the given regexp pattern. +// +// For example: +// +// r := mux.NewRouter() +// r.Host("www.example.com") +// r.Host("{subdomain}.domain.com") +// r.Host("{subdomain:[a-z]+}.domain.com") +// +// Variable names must be unique in a given route. They can be retrieved +// calling mux.Vars(request). +func (r *Route) Host(tpl string) *Route { + r.err = r.addRegexpMatcher(tpl, true, false, false) + return r +} + +// MatcherFunc ---------------------------------------------------------------- + +// MatcherFunc is the function signature used by custom matchers. +type MatcherFunc func(*http.Request, *RouteMatch) bool + +// Match returns the match for a given request. +func (m MatcherFunc) Match(r *http.Request, match *RouteMatch) bool { + return m(r, match) +} + +// MatcherFunc adds a custom function to be used as request matcher. +func (r *Route) MatcherFunc(f MatcherFunc) *Route { + return r.addMatcher(f) +} + +// Methods -------------------------------------------------------------------- + +// methodMatcher matches the request against HTTP methods. +type methodMatcher []string + +func (m methodMatcher) Match(r *http.Request, match *RouteMatch) bool { + return matchInArray(m, r.Method) +} + +// Methods adds a matcher for HTTP methods. +// It accepts a sequence of one or more methods to be matched, e.g.: +// "GET", "POST", "PUT". +func (r *Route) Methods(methods ...string) *Route { + for k, v := range methods { + methods[k] = strings.ToUpper(v) + } + return r.addMatcher(methodMatcher(methods)) +} + +// Path ----------------------------------------------------------------------- + +// Path adds a matcher for the URL path. +// It accepts a template with zero or more URL variables enclosed by {}. The +// template must start with a "/". +// Variables can define an optional regexp pattern to be matched: +// +// - {name} matches anything until the next slash. +// +// - {name:pattern} matches the given regexp pattern. +// +// For example: +// +// r := mux.NewRouter() +// r.Path("/products/").Handler(ProductsHandler) +// r.Path("/products/{key}").Handler(ProductsHandler) +// r.Path("/articles/{category}/{id:[0-9]+}"). +// Handler(ArticleHandler) +// +// Variable names must be unique in a given route. They can be retrieved +// calling mux.Vars(request). +func (r *Route) Path(tpl string) *Route { + r.err = r.addRegexpMatcher(tpl, false, false, false) + return r +} + +// PathPrefix ----------------------------------------------------------------- + +// PathPrefix adds a matcher for the URL path prefix. This matches if the given +// template is a prefix of the full URL path. See Route.Path() for details on +// the tpl argument. +// +// Note that it does not treat slashes specially ("/foobar/" will be matched by +// the prefix "/foo") so you may want to use a trailing slash here. +// +// Also note that the setting of Router.StrictSlash() has no effect on routes +// with a PathPrefix matcher. +func (r *Route) PathPrefix(tpl string) *Route { + r.err = r.addRegexpMatcher(tpl, false, true, false) + return r +} + +// Query ---------------------------------------------------------------------- + +// Queries adds a matcher for URL query values. +// It accepts a sequence of key/value pairs. Values may define variables. +// For example: +// +// r := mux.NewRouter() +// r.Queries("foo", "bar", "id", "{id:[0-9]+}") +// +// The above route will only match if the URL contains the defined queries +// values, e.g.: ?foo=bar&id=42. +// +// It the value is an empty string, it will match any value if the key is set. +// +// Variables can define an optional regexp pattern to be matched: +// +// - {name} matches anything until the next slash. +// +// - {name:pattern} matches the given regexp pattern. +func (r *Route) Queries(pairs ...string) *Route { + length := len(pairs) + if length%2 != 0 { + r.err = fmt.Errorf( + "mux: number of parameters must be multiple of 2, got %v", pairs) + return nil + } + for i := 0; i < length; i += 2 { + if r.err = r.addRegexpMatcher(pairs[i]+"="+pairs[i+1], false, false, true); r.err != nil { + return r + } + } + + return r +} + +// Schemes -------------------------------------------------------------------- + +// schemeMatcher matches the request against URL schemes. +type schemeMatcher []string + +func (m schemeMatcher) Match(r *http.Request, match *RouteMatch) bool { + return matchInArray(m, r.URL.Scheme) +} + +// Schemes adds a matcher for URL schemes. +// It accepts a sequence of schemes to be matched, e.g.: "http", "https". +func (r *Route) Schemes(schemes ...string) *Route { + for k, v := range schemes { + schemes[k] = strings.ToLower(v) + } + return r.addMatcher(schemeMatcher(schemes)) +} + +// BuildVarsFunc -------------------------------------------------------------- + +// BuildVarsFunc is the function signature used by custom build variable +// functions (which can modify route variables before a route's URL is built). +type BuildVarsFunc func(map[string]string) map[string]string + +// BuildVarsFunc adds a custom function to be used to modify build variables +// before a route's URL is built. +func (r *Route) BuildVarsFunc(f BuildVarsFunc) *Route { + r.buildVarsFunc = f + return r +} + +// Subrouter ------------------------------------------------------------------ + +// Subrouter creates a subrouter for the route. +// +// It will test the inner routes only if the parent route matched. For example: +// +// r := mux.NewRouter() +// s := r.Host("www.example.com").Subrouter() +// s.HandleFunc("/products/", ProductsHandler) +// s.HandleFunc("/products/{key}", ProductHandler) +// s.HandleFunc("/articles/{category}/{id:[0-9]+}"), ArticleHandler) +// +// Here, the routes registered in the subrouter won't be tested if the host +// doesn't match. +func (r *Route) Subrouter() *Router { + router := &Router{parent: r, strictSlash: r.strictSlash} + r.addMatcher(router) + return router +} + +// ---------------------------------------------------------------------------- +// URL building +// ---------------------------------------------------------------------------- + +// URL builds a URL for the route. +// +// It accepts a sequence of key/value pairs for the route variables. For +// example, given this route: +// +// r := mux.NewRouter() +// r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler). +// Name("article") +// +// ...a URL for it can be built using: +// +// url, err := r.Get("article").URL("category", "technology", "id", "42") +// +// ...which will return an url.URL with the following path: +// +// "/articles/technology/42" +// +// This also works for host variables: +// +// r := mux.NewRouter() +// r.Host("{subdomain}.domain.com"). +// HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler). +// Name("article") +// +// // url.String() will be "http://news.domain.com/articles/technology/42" +// url, err := r.Get("article").URL("subdomain", "news", +// "category", "technology", +// "id", "42") +// +// All variables defined in the route are required, and their values must +// conform to the corresponding patterns. +func (r *Route) URL(pairs ...string) (*url.URL, error) { + if r.err != nil { + return nil, r.err + } + if r.regexp == nil { + return nil, errors.New("mux: route doesn't have a host or path") + } + values, err := r.prepareVars(pairs...) + if err != nil { + return nil, err + } + var scheme, host, path string + if r.regexp.host != nil { + // Set a default scheme. + scheme = "http" + if host, err = r.regexp.host.url(values); err != nil { + return nil, err + } + } + if r.regexp.path != nil { + if path, err = r.regexp.path.url(values); err != nil { + return nil, err + } + } + return &url.URL{ + Scheme: scheme, + Host: host, + Path: path, + }, nil +} + +// URLHost builds the host part of the URL for a route. See Route.URL(). +// +// The route must have a host defined. +func (r *Route) URLHost(pairs ...string) (*url.URL, error) { + if r.err != nil { + return nil, r.err + } + if r.regexp == nil || r.regexp.host == nil { + return nil, errors.New("mux: route doesn't have a host") + } + values, err := r.prepareVars(pairs...) + if err != nil { + return nil, err + } + host, err := r.regexp.host.url(values) + if err != nil { + return nil, err + } + return &url.URL{ + Scheme: "http", + Host: host, + }, nil +} + +// URLPath builds the path part of the URL for a route. See Route.URL(). +// +// The route must have a path defined. +func (r *Route) URLPath(pairs ...string) (*url.URL, error) { + if r.err != nil { + return nil, r.err + } + if r.regexp == nil || r.regexp.path == nil { + return nil, errors.New("mux: route doesn't have a path") + } + values, err := r.prepareVars(pairs...) + if err != nil { + return nil, err + } + path, err := r.regexp.path.url(values) + if err != nil { + return nil, err + } + return &url.URL{ + Path: path, + }, nil +} + +// GetPathTemplate returns the template used to build the +// route match. +// This is useful for building simple REST API documentation and for instrumentation +// against third-party services. +// An error will be returned if the route does not define a path. +func (r *Route) GetPathTemplate() (string, error) { + if r.err != nil { + return "", r.err + } + if r.regexp == nil || r.regexp.path == nil { + return "", errors.New("mux: route doesn't have a path") + } + return r.regexp.path.template, nil +} + +// GetHostTemplate returns the template used to build the +// route match. +// This is useful for building simple REST API documentation and for instrumentation +// against third-party services. +// An error will be returned if the route does not define a host. +func (r *Route) GetHostTemplate() (string, error) { + if r.err != nil { + return "", r.err + } + if r.regexp == nil || r.regexp.host == nil { + return "", errors.New("mux: route doesn't have a host") + } + return r.regexp.host.template, nil +} + +// prepareVars converts the route variable pairs into a map. If the route has a +// BuildVarsFunc, it is invoked. +func (r *Route) prepareVars(pairs ...string) (map[string]string, error) { + m, err := mapFromPairsToString(pairs...) + if err != nil { + return nil, err + } + return r.buildVars(m), nil +} + +func (r *Route) buildVars(m map[string]string) map[string]string { + if r.parent != nil { + m = r.parent.buildVars(m) + } + if r.buildVarsFunc != nil { + m = r.buildVarsFunc(m) + } + return m +} + +// ---------------------------------------------------------------------------- +// parentRoute +// ---------------------------------------------------------------------------- + +// parentRoute allows routes to know about parent host and path definitions. +type parentRoute interface { + getNamedRoutes() map[string]*Route + getRegexpGroup() *routeRegexpGroup + buildVars(map[string]string) map[string]string +} + +// getNamedRoutes returns the map where named routes are registered. +func (r *Route) getNamedRoutes() map[string]*Route { + if r.parent == nil { + // During tests router is not always set. + r.parent = NewRouter() + } + return r.parent.getNamedRoutes() +} + +// getRegexpGroup returns regexp definitions from this route. +func (r *Route) getRegexpGroup() *routeRegexpGroup { + if r.regexp == nil { + if r.parent == nil { + // During tests router is not always set. + r.parent = NewRouter() + } + regexp := r.parent.getRegexpGroup() + if regexp == nil { + r.regexp = new(routeRegexpGroup) + } else { + // Copy. + r.regexp = &routeRegexpGroup{ + host: regexp.host, + path: regexp.path, + queries: regexp.queries, + } + } + } + return r.regexp +} diff --git a/contrib/backends/nntpchand/src/vendor/github.com/gorilla/securecookie/.travis.yml b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/securecookie/.travis.yml new file mode 100644 index 0000000..6f440f1 --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/securecookie/.travis.yml @@ -0,0 +1,19 @@ +language: go +sudo: false + +matrix: + include: + - go: 1.3 + - go: 1.4 + - go: 1.5 + - go: 1.6 + - go: 1.7 + - go: tip + allow_failures: + - go: tip + +script: + - go get -t -v ./... + - diff -u <(echo -n) <(gofmt -d .) + - go vet $(go list ./... | grep -v /vendor/) + - go test -v -race ./... diff --git a/contrib/backends/nntpchand/src/vendor/github.com/gorilla/securecookie/LICENSE b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/securecookie/LICENSE new file mode 100644 index 0000000..0e5fb87 --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/securecookie/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2012 Rodrigo Moraes. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/contrib/backends/nntpchand/src/vendor/github.com/gorilla/securecookie/README.md b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/securecookie/README.md new file mode 100644 index 0000000..aa7bd1a --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/securecookie/README.md @@ -0,0 +1,80 @@ +securecookie +============ +[![GoDoc](https://godoc.org/github.com/gorilla/securecookie?status.svg)](https://godoc.org/github.com/gorilla/securecookie) [![Build Status](https://travis-ci.org/gorilla/securecookie.png?branch=master)](https://travis-ci.org/gorilla/securecookie) +[![Sourcegraph](https://sourcegraph.com/github.com/gorilla/securecookie/-/badge.svg)](https://sourcegraph.com/github.com/gorilla/securecookie?badge) + + +securecookie encodes and decodes authenticated and optionally encrypted +cookie values. + +Secure cookies can't be forged, because their values are validated using HMAC. +When encrypted, the content is also inaccessible to malicious eyes. It is still +recommended that sensitive data not be stored in cookies, and that HTTPS be used +to prevent cookie [replay attacks](https://en.wikipedia.org/wiki/Replay_attack). + +## Examples + +To use it, first create a new SecureCookie instance: + +```go +// Hash keys should be at least 32 bytes long +var hashKey = []byte("very-secret") +// Block keys should be 16 bytes (AES-128) or 32 bytes (AES-256) long. +// Shorter keys may weaken the encryption used. +var blockKey = []byte("a-lot-secret") +var s = securecookie.New(hashKey, blockKey) +``` + +The hashKey is required, used to authenticate the cookie value using HMAC. +It is recommended to use a key with 32 or 64 bytes. + +The blockKey is optional, used to encrypt the cookie value -- set it to nil +to not use encryption. If set, the length must correspond to the block size +of the encryption algorithm. For AES, used by default, valid lengths are +16, 24, or 32 bytes to select AES-128, AES-192, or AES-256. + +Strong keys can be created using the convenience function GenerateRandomKey(). + +Once a SecureCookie instance is set, use it to encode a cookie value: + +```go +func SetCookieHandler(w http.ResponseWriter, r *http.Request) { + value := map[string]string{ + "foo": "bar", + } + if encoded, err := s.Encode("cookie-name", value); err == nil { + cookie := &http.Cookie{ + Name: "cookie-name", + Value: encoded, + Path: "/", + Secure: true, + HttpOnly: true, + } + http.SetCookie(w, cookie) + } +} +``` + +Later, use the same SecureCookie instance to decode and validate a cookie +value: + +```go +func ReadCookieHandler(w http.ResponseWriter, r *http.Request) { + if cookie, err := r.Cookie("cookie-name"); err == nil { + value := make(map[string]string) + if err = s2.Decode("cookie-name", cookie.Value, &value); err == nil { + fmt.Fprintf(w, "The value of foo is %q", value["foo"]) + } + } +} +``` + +We stored a map[string]string, but secure cookies can hold any value that +can be encoded using `encoding/gob`. To store custom types, they must be +registered first using gob.Register(). For basic types this is not needed; +it works out of the box. An optional JSON encoder that uses `encoding/json` is +available for types compatible with JSON. + +## License + +BSD licensed. See the LICENSE file for details. diff --git a/contrib/backends/nntpchand/src/vendor/github.com/gorilla/securecookie/doc.go b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/securecookie/doc.go new file mode 100644 index 0000000..ae89408 --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/securecookie/doc.go @@ -0,0 +1,61 @@ +// Copyright 2012 The Gorilla 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 securecookie encodes and decodes authenticated and optionally +encrypted cookie values. + +Secure cookies can't be forged, because their values are validated using HMAC. +When encrypted, the content is also inaccessible to malicious eyes. + +To use it, first create a new SecureCookie instance: + + var hashKey = []byte("very-secret") + var blockKey = []byte("a-lot-secret") + var s = securecookie.New(hashKey, blockKey) + +The hashKey is required, used to authenticate the cookie value using HMAC. +It is recommended to use a key with 32 or 64 bytes. + +The blockKey is optional, used to encrypt the cookie value -- set it to nil +to not use encryption. If set, the length must correspond to the block size +of the encryption algorithm. For AES, used by default, valid lengths are +16, 24, or 32 bytes to select AES-128, AES-192, or AES-256. + +Strong keys can be created using the convenience function GenerateRandomKey(). + +Once a SecureCookie instance is set, use it to encode a cookie value: + + func SetCookieHandler(w http.ResponseWriter, r *http.Request) { + value := map[string]string{ + "foo": "bar", + } + if encoded, err := s.Encode("cookie-name", value); err == nil { + cookie := &http.Cookie{ + Name: "cookie-name", + Value: encoded, + Path: "/", + } + http.SetCookie(w, cookie) + } + } + +Later, use the same SecureCookie instance to decode and validate a cookie +value: + + func ReadCookieHandler(w http.ResponseWriter, r *http.Request) { + if cookie, err := r.Cookie("cookie-name"); err == nil { + value := make(map[string]string) + if err = s2.Decode("cookie-name", cookie.Value, &value); err == nil { + fmt.Fprintf(w, "The value of foo is %q", value["foo"]) + } + } + } + +We stored a map[string]string, but secure cookies can hold any value that +can be encoded using encoding/gob. To store custom types, they must be +registered first using gob.Register(). For basic types this is not needed; +it works out of the box. +*/ +package securecookie diff --git a/contrib/backends/nntpchand/src/vendor/github.com/gorilla/securecookie/fuzz.go b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/securecookie/fuzz.go new file mode 100644 index 0000000..e4d0534 --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/securecookie/fuzz.go @@ -0,0 +1,25 @@ +// +build gofuzz + +package securecookie + +var hashKey = []byte("very-secret12345") +var blockKey = []byte("a-lot-secret1234") +var s = New(hashKey, blockKey) + +type Cookie struct { + B bool + I int + S string +} + +func Fuzz(data []byte) int { + datas := string(data) + var c Cookie + if err := s.Decode("fuzz", datas, &c); err != nil { + return 0 + } + if _, err := s.Encode("fuzz", c); err != nil { + panic(err) + } + return 1 +} diff --git a/contrib/backends/nntpchand/src/vendor/github.com/gorilla/securecookie/securecookie.go b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/securecookie/securecookie.go new file mode 100644 index 0000000..cd4e097 --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/securecookie/securecookie.go @@ -0,0 +1,646 @@ +// Copyright 2012 The Gorilla 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 securecookie + +import ( + "bytes" + "crypto/aes" + "crypto/cipher" + "crypto/hmac" + "crypto/rand" + "crypto/sha256" + "crypto/subtle" + "encoding/base64" + "encoding/gob" + "encoding/json" + "fmt" + "hash" + "io" + "strconv" + "strings" + "time" +) + +// Error is the interface of all errors returned by functions in this library. +type Error interface { + error + + // IsUsage returns true for errors indicating the client code probably + // uses this library incorrectly. For example, the client may have + // failed to provide a valid hash key, or may have failed to configure + // the Serializer adequately for encoding value. + IsUsage() bool + + // IsDecode returns true for errors indicating that a cookie could not + // be decoded and validated. Since cookies are usually untrusted + // user-provided input, errors of this type should be expected. + // Usually, the proper action is simply to reject the request. + IsDecode() bool + + // IsInternal returns true for unexpected errors occurring in the + // securecookie implementation. + IsInternal() bool + + // Cause, if it returns a non-nil value, indicates that this error was + // propagated from some underlying library. If this method returns nil, + // this error was raised directly by this library. + // + // Cause is provided principally for debugging/logging purposes; it is + // rare that application logic should perform meaningfully different + // logic based on Cause. See, for example, the caveats described on + // (MultiError).Cause(). + Cause() error +} + +// errorType is a bitmask giving the error type(s) of an cookieError value. +type errorType int + +const ( + usageError = errorType(1 << iota) + decodeError + internalError +) + +type cookieError struct { + typ errorType + msg string + cause error +} + +func (e cookieError) IsUsage() bool { return (e.typ & usageError) != 0 } +func (e cookieError) IsDecode() bool { return (e.typ & decodeError) != 0 } +func (e cookieError) IsInternal() bool { return (e.typ & internalError) != 0 } + +func (e cookieError) Cause() error { return e.cause } + +func (e cookieError) Error() string { + parts := []string{"securecookie: "} + if e.msg == "" { + parts = append(parts, "error") + } else { + parts = append(parts, e.msg) + } + if c := e.Cause(); c != nil { + parts = append(parts, " - caused by: ", c.Error()) + } + return strings.Join(parts, "") +} + +var ( + errGeneratingIV = cookieError{typ: internalError, msg: "failed to generate random iv"} + + errNoCodecs = cookieError{typ: usageError, msg: "no codecs provided"} + errHashKeyNotSet = cookieError{typ: usageError, msg: "hash key is not set"} + errBlockKeyNotSet = cookieError{typ: usageError, msg: "block key is not set"} + errEncodedValueTooLong = cookieError{typ: usageError, msg: "the value is too long"} + + errValueToDecodeTooLong = cookieError{typ: decodeError, msg: "the value is too long"} + errTimestampInvalid = cookieError{typ: decodeError, msg: "invalid timestamp"} + errTimestampTooNew = cookieError{typ: decodeError, msg: "timestamp is too new"} + errTimestampExpired = cookieError{typ: decodeError, msg: "expired timestamp"} + errDecryptionFailed = cookieError{typ: decodeError, msg: "the value could not be decrypted"} + errValueNotByte = cookieError{typ: decodeError, msg: "value not a []byte."} + errValueNotBytePtr = cookieError{typ: decodeError, msg: "value not a pointer to []byte."} + + // ErrMacInvalid indicates that cookie decoding failed because the HMAC + // could not be extracted and verified. Direct use of this error + // variable is deprecated; it is public only for legacy compatibility, + // and may be privatized in the future, as it is rarely useful to + // distinguish between this error and other Error implementations. + ErrMacInvalid = cookieError{typ: decodeError, msg: "the value is not valid"} +) + +// Codec defines an interface to encode and decode cookie values. +type Codec interface { + Encode(name string, value interface{}) (string, error) + Decode(name, value string, dst interface{}) error +} + +// New returns a new SecureCookie. +// +// hashKey is required, used to authenticate values using HMAC. Create it using +// GenerateRandomKey(). It is recommended to use a key with 32 or 64 bytes. +// +// blockKey is optional, used to encrypt values. Create it using +// GenerateRandomKey(). The key length must correspond to the block size +// of the encryption algorithm. For AES, used by default, valid lengths are +// 16, 24, or 32 bytes to select AES-128, AES-192, or AES-256. +// The default encoder used for cookie serialization is encoding/gob. +// +// Note that keys created using GenerateRandomKey() are not automatically +// persisted. New keys will be created when the application is restarted, and +// previously issued cookies will not be able to be decoded. +func New(hashKey, blockKey []byte) *SecureCookie { + s := &SecureCookie{ + hashKey: hashKey, + blockKey: blockKey, + hashFunc: sha256.New, + maxAge: 86400 * 30, + maxLength: 4096, + sz: GobEncoder{}, + } + if hashKey == nil { + s.err = errHashKeyNotSet + } + if blockKey != nil { + s.BlockFunc(aes.NewCipher) + } + return s +} + +// SecureCookie encodes and decodes authenticated and optionally encrypted +// cookie values. +type SecureCookie struct { + hashKey []byte + hashFunc func() hash.Hash + blockKey []byte + block cipher.Block + maxLength int + maxAge int64 + minAge int64 + err error + sz Serializer + // For testing purposes, the function that returns the current timestamp. + // If not set, it will use time.Now().UTC().Unix(). + timeFunc func() int64 +} + +// Serializer provides an interface for providing custom serializers for cookie +// values. +type Serializer interface { + Serialize(src interface{}) ([]byte, error) + Deserialize(src []byte, dst interface{}) error +} + +// GobEncoder encodes cookie values using encoding/gob. This is the simplest +// encoder and can handle complex types via gob.Register. +type GobEncoder struct{} + +// JSONEncoder encodes cookie values using encoding/json. Users who wish to +// encode complex types need to satisfy the json.Marshaller and +// json.Unmarshaller interfaces. +type JSONEncoder struct{} + +// NopEncoder does not encode cookie values, and instead simply accepts a []byte +// (as an interface{}) and returns a []byte. This is particularly useful when +// you encoding an object upstream and do not wish to re-encode it. +type NopEncoder struct{} + +// MaxLength restricts the maximum length, in bytes, for the cookie value. +// +// Default is 4096, which is the maximum value accepted by Internet Explorer. +func (s *SecureCookie) MaxLength(value int) *SecureCookie { + s.maxLength = value + return s +} + +// MaxAge restricts the maximum age, in seconds, for the cookie value. +// +// Default is 86400 * 30. Set it to 0 for no restriction. +func (s *SecureCookie) MaxAge(value int) *SecureCookie { + s.maxAge = int64(value) + return s +} + +// MinAge restricts the minimum age, in seconds, for the cookie value. +// +// Default is 0 (no restriction). +func (s *SecureCookie) MinAge(value int) *SecureCookie { + s.minAge = int64(value) + return s +} + +// HashFunc sets the hash function used to create HMAC. +// +// Default is crypto/sha256.New. +func (s *SecureCookie) HashFunc(f func() hash.Hash) *SecureCookie { + s.hashFunc = f + return s +} + +// BlockFunc sets the encryption function used to create a cipher.Block. +// +// Default is crypto/aes.New. +func (s *SecureCookie) BlockFunc(f func([]byte) (cipher.Block, error)) *SecureCookie { + if s.blockKey == nil { + s.err = errBlockKeyNotSet + } else if block, err := f(s.blockKey); err == nil { + s.block = block + } else { + s.err = cookieError{cause: err, typ: usageError} + } + return s +} + +// Encoding sets the encoding/serialization method for cookies. +// +// Default is encoding/gob. To encode special structures using encoding/gob, +// they must be registered first using gob.Register(). +func (s *SecureCookie) SetSerializer(sz Serializer) *SecureCookie { + s.sz = sz + + return s +} + +// Encode encodes a cookie value. +// +// It serializes, optionally encrypts, signs with a message authentication code, +// and finally encodes the value. +// +// The name argument is the cookie name. It is stored with the encoded value. +// The value argument is the value to be encoded. It can be any value that can +// be encoded using the currently selected serializer; see SetSerializer(). +// +// It is the client's responsibility to ensure that value, when encoded using +// the current serialization/encryption settings on s and then base64-encoded, +// is shorter than the maximum permissible length. +func (s *SecureCookie) Encode(name string, value interface{}) (string, error) { + if s.err != nil { + return "", s.err + } + if s.hashKey == nil { + s.err = errHashKeyNotSet + return "", s.err + } + var err error + var b []byte + // 1. Serialize. + if b, err = s.sz.Serialize(value); err != nil { + return "", cookieError{cause: err, typ: usageError} + } + // 2. Encrypt (optional). + if s.block != nil { + if b, err = encrypt(s.block, b); err != nil { + return "", cookieError{cause: err, typ: usageError} + } + } + b = encode(b) + // 3. Create MAC for "name|date|value". Extra pipe to be used later. + b = []byte(fmt.Sprintf("%s|%d|%s|", name, s.timestamp(), b)) + mac := createMac(hmac.New(s.hashFunc, s.hashKey), b[:len(b)-1]) + // Append mac, remove name. + b = append(b, mac...)[len(name)+1:] + // 4. Encode to base64. + b = encode(b) + // 5. Check length. + if s.maxLength != 0 && len(b) > s.maxLength { + return "", errEncodedValueTooLong + } + // Done. + return string(b), nil +} + +// Decode decodes a cookie value. +// +// It decodes, verifies a message authentication code, optionally decrypts and +// finally deserializes the value. +// +// The name argument is the cookie name. It must be the same name used when +// it was stored. The value argument is the encoded cookie value. The dst +// argument is where the cookie will be decoded. It must be a pointer. +func (s *SecureCookie) Decode(name, value string, dst interface{}) error { + if s.err != nil { + return s.err + } + if s.hashKey == nil { + s.err = errHashKeyNotSet + return s.err + } + // 1. Check length. + if s.maxLength != 0 && len(value) > s.maxLength { + return errValueToDecodeTooLong + } + // 2. Decode from base64. + b, err := decode([]byte(value)) + if err != nil { + return err + } + // 3. Verify MAC. Value is "date|value|mac". + parts := bytes.SplitN(b, []byte("|"), 3) + if len(parts) != 3 { + return ErrMacInvalid + } + h := hmac.New(s.hashFunc, s.hashKey) + b = append([]byte(name+"|"), b[:len(b)-len(parts[2])-1]...) + if err = verifyMac(h, b, parts[2]); err != nil { + return err + } + // 4. Verify date ranges. + var t1 int64 + if t1, err = strconv.ParseInt(string(parts[0]), 10, 64); err != nil { + return errTimestampInvalid + } + t2 := s.timestamp() + if s.minAge != 0 && t1 > t2-s.minAge { + return errTimestampTooNew + } + if s.maxAge != 0 && t1 < t2-s.maxAge { + return errTimestampExpired + } + // 5. Decrypt (optional). + b, err = decode(parts[1]) + if err != nil { + return err + } + if s.block != nil { + if b, err = decrypt(s.block, b); err != nil { + return err + } + } + // 6. Deserialize. + if err = s.sz.Deserialize(b, dst); err != nil { + return cookieError{cause: err, typ: decodeError} + } + // Done. + return nil +} + +// timestamp returns the current timestamp, in seconds. +// +// For testing purposes, the function that generates the timestamp can be +// overridden. If not set, it will return time.Now().UTC().Unix(). +func (s *SecureCookie) timestamp() int64 { + if s.timeFunc == nil { + return time.Now().UTC().Unix() + } + return s.timeFunc() +} + +// Authentication ------------------------------------------------------------- + +// createMac creates a message authentication code (MAC). +func createMac(h hash.Hash, value []byte) []byte { + h.Write(value) + return h.Sum(nil) +} + +// verifyMac verifies that a message authentication code (MAC) is valid. +func verifyMac(h hash.Hash, value []byte, mac []byte) error { + mac2 := createMac(h, value) + // Check that both MACs are of equal length, as subtle.ConstantTimeCompare + // does not do this prior to Go 1.4. + if len(mac) == len(mac2) && subtle.ConstantTimeCompare(mac, mac2) == 1 { + return nil + } + return ErrMacInvalid +} + +// Encryption ----------------------------------------------------------------- + +// encrypt encrypts a value using the given block in counter mode. +// +// A random initialization vector (http://goo.gl/zF67k) with the length of the +// block size is prepended to the resulting ciphertext. +func encrypt(block cipher.Block, value []byte) ([]byte, error) { + iv := GenerateRandomKey(block.BlockSize()) + if iv == nil { + return nil, errGeneratingIV + } + // Encrypt it. + stream := cipher.NewCTR(block, iv) + stream.XORKeyStream(value, value) + // Return iv + ciphertext. + return append(iv, value...), nil +} + +// decrypt decrypts a value using the given block in counter mode. +// +// The value to be decrypted must be prepended by a initialization vector +// (http://goo.gl/zF67k) with the length of the block size. +func decrypt(block cipher.Block, value []byte) ([]byte, error) { + size := block.BlockSize() + if len(value) > size { + // Extract iv. + iv := value[:size] + // Extract ciphertext. + value = value[size:] + // Decrypt it. + stream := cipher.NewCTR(block, iv) + stream.XORKeyStream(value, value) + return value, nil + } + return nil, errDecryptionFailed +} + +// Serialization -------------------------------------------------------------- + +// Serialize encodes a value using gob. +func (e GobEncoder) Serialize(src interface{}) ([]byte, error) { + buf := new(bytes.Buffer) + enc := gob.NewEncoder(buf) + if err := enc.Encode(src); err != nil { + return nil, cookieError{cause: err, typ: usageError} + } + return buf.Bytes(), nil +} + +// Deserialize decodes a value using gob. +func (e GobEncoder) Deserialize(src []byte, dst interface{}) error { + dec := gob.NewDecoder(bytes.NewBuffer(src)) + if err := dec.Decode(dst); err != nil { + return cookieError{cause: err, typ: decodeError} + } + return nil +} + +// Serialize encodes a value using encoding/json. +func (e JSONEncoder) Serialize(src interface{}) ([]byte, error) { + buf := new(bytes.Buffer) + enc := json.NewEncoder(buf) + if err := enc.Encode(src); err != nil { + return nil, cookieError{cause: err, typ: usageError} + } + return buf.Bytes(), nil +} + +// Deserialize decodes a value using encoding/json. +func (e JSONEncoder) Deserialize(src []byte, dst interface{}) error { + dec := json.NewDecoder(bytes.NewReader(src)) + if err := dec.Decode(dst); err != nil { + return cookieError{cause: err, typ: decodeError} + } + return nil +} + +// Serialize passes a []byte through as-is. +func (e NopEncoder) Serialize(src interface{}) ([]byte, error) { + if b, ok := src.([]byte); ok { + return b, nil + } + + return nil, errValueNotByte +} + +// Deserialize passes a []byte through as-is. +func (e NopEncoder) Deserialize(src []byte, dst interface{}) error { + if dat, ok := dst.(*[]byte); ok { + *dat = src + return nil + } + return errValueNotBytePtr +} + +// Encoding ------------------------------------------------------------------- + +// encode encodes a value using base64. +func encode(value []byte) []byte { + encoded := make([]byte, base64.URLEncoding.EncodedLen(len(value))) + base64.URLEncoding.Encode(encoded, value) + return encoded +} + +// decode decodes a cookie using base64. +func decode(value []byte) ([]byte, error) { + decoded := make([]byte, base64.URLEncoding.DecodedLen(len(value))) + b, err := base64.URLEncoding.Decode(decoded, value) + if err != nil { + return nil, cookieError{cause: err, typ: decodeError, msg: "base64 decode failed"} + } + return decoded[:b], nil +} + +// Helpers -------------------------------------------------------------------- + +// GenerateRandomKey creates a random key with the given length in bytes. +// On failure, returns nil. +// +// Callers should explicitly check for the possibility of a nil return, treat +// it as a failure of the system random number generator, and not continue. +func GenerateRandomKey(length int) []byte { + k := make([]byte, length) + if _, err := io.ReadFull(rand.Reader, k); err != nil { + return nil + } + return k +} + +// CodecsFromPairs returns a slice of SecureCookie instances. +// +// It is a convenience function to create a list of codecs for key rotation. Note +// that the generated Codecs will have the default options applied: callers +// should iterate over each Codec and type-assert the underlying *SecureCookie to +// change these. +// +// Example: +// +// codecs := securecookie.CodecsFromPairs( +// []byte("new-hash-key"), +// []byte("new-block-key"), +// []byte("old-hash-key"), +// []byte("old-block-key"), +// ) +// +// // Modify each instance. +// for _, s := range codecs { +// if cookie, ok := s.(*securecookie.SecureCookie); ok { +// cookie.MaxAge(86400 * 7) +// cookie.SetSerializer(securecookie.JSONEncoder{}) +// cookie.HashFunc(sha512.New512_256) +// } +// } +// +func CodecsFromPairs(keyPairs ...[]byte) []Codec { + codecs := make([]Codec, len(keyPairs)/2+len(keyPairs)%2) + for i := 0; i < len(keyPairs); i += 2 { + var blockKey []byte + if i+1 < len(keyPairs) { + blockKey = keyPairs[i+1] + } + codecs[i/2] = New(keyPairs[i], blockKey) + } + return codecs +} + +// EncodeMulti encodes a cookie value using a group of codecs. +// +// The codecs are tried in order. Multiple codecs are accepted to allow +// key rotation. +// +// On error, may return a MultiError. +func EncodeMulti(name string, value interface{}, codecs ...Codec) (string, error) { + if len(codecs) == 0 { + return "", errNoCodecs + } + + var errors MultiError + for _, codec := range codecs { + encoded, err := codec.Encode(name, value) + if err == nil { + return encoded, nil + } + errors = append(errors, err) + } + return "", errors +} + +// DecodeMulti decodes a cookie value using a group of codecs. +// +// The codecs are tried in order. Multiple codecs are accepted to allow +// key rotation. +// +// On error, may return a MultiError. +func DecodeMulti(name string, value string, dst interface{}, codecs ...Codec) error { + if len(codecs) == 0 { + return errNoCodecs + } + + var errors MultiError + for _, codec := range codecs { + err := codec.Decode(name, value, dst) + if err == nil { + return nil + } + errors = append(errors, err) + } + return errors +} + +// MultiError groups multiple errors. +type MultiError []error + +func (m MultiError) IsUsage() bool { return m.any(func(e Error) bool { return e.IsUsage() }) } +func (m MultiError) IsDecode() bool { return m.any(func(e Error) bool { return e.IsDecode() }) } +func (m MultiError) IsInternal() bool { return m.any(func(e Error) bool { return e.IsInternal() }) } + +// Cause returns nil for MultiError; there is no unique underlying cause in the +// general case. +// +// Note: we could conceivably return a non-nil Cause only when there is exactly +// one child error with a Cause. However, it would be brittle for client code +// to rely on the arity of causes inside a MultiError, so we have opted not to +// provide this functionality. Clients which really wish to access the Causes +// of the underlying errors are free to iterate through the errors themselves. +func (m MultiError) Cause() error { return nil } + +func (m MultiError) Error() string { + s, n := "", 0 + for _, e := range m { + if e != nil { + if n == 0 { + s = e.Error() + } + n++ + } + } + switch n { + case 0: + return "(0 errors)" + case 1: + return s + case 2: + return s + " (and 1 other error)" + } + return fmt.Sprintf("%s (and %d other errors)", s, n-1) +} + +// any returns true if any element of m is an Error for which pred returns true. +func (m MultiError) any(pred func(Error) bool) bool { + for _, e := range m { + if ourErr, ok := e.(Error); ok && pred(ourErr) { + return true + } + } + return false +} diff --git a/contrib/backends/nntpchand/src/vendor/github.com/gorilla/securecookie/securecookie_test.go b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/securecookie/securecookie_test.go new file mode 100644 index 0000000..2b0f8a1 --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/securecookie/securecookie_test.go @@ -0,0 +1,301 @@ +// Copyright 2012 The Gorilla 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 securecookie + +import ( + "crypto/aes" + "crypto/hmac" + "crypto/sha256" + "encoding/base64" + "fmt" + "reflect" + "strings" + "testing" +) + +// Asserts that cookieError and MultiError are Error implementations. +var _ Error = cookieError{} +var _ Error = MultiError{} + +var testCookies = []interface{}{ + map[string]string{"foo": "bar"}, + map[string]string{"baz": "ding"}, +} + +var testStrings = []string{"foo", "bar", "baz"} + +func TestSecureCookie(t *testing.T) { + // TODO test too old / too new timestamps + s1 := New([]byte("12345"), []byte("1234567890123456")) + s2 := New([]byte("54321"), []byte("6543210987654321")) + value := map[string]interface{}{ + "foo": "bar", + "baz": 128, + } + + for i := 0; i < 50; i++ { + // Running this multiple times to check if any special character + // breaks encoding/decoding. + encoded, err1 := s1.Encode("sid", value) + if err1 != nil { + t.Error(err1) + continue + } + dst := make(map[string]interface{}) + err2 := s1.Decode("sid", encoded, &dst) + if err2 != nil { + t.Fatalf("%v: %v", err2, encoded) + } + if !reflect.DeepEqual(dst, value) { + t.Fatalf("Expected %v, got %v.", value, dst) + } + dst2 := make(map[string]interface{}) + err3 := s2.Decode("sid", encoded, &dst2) + if err3 == nil { + t.Fatalf("Expected failure decoding.") + } + err4, ok := err3.(Error) + if !ok { + t.Fatalf("Expected error to implement Error, got: %#v", err3) + } + if !err4.IsDecode() { + t.Fatalf("Expected DecodeError, got: %#v", err4) + } + + // Test other error type flags. + if err4.IsUsage() { + t.Fatalf("Expected IsUsage() == false, got: %#v", err4) + } + if err4.IsInternal() { + t.Fatalf("Expected IsInternal() == false, got: %#v", err4) + } + } +} + +func TestSecureCookieNilKey(t *testing.T) { + s1 := New(nil, nil) + value := map[string]interface{}{ + "foo": "bar", + "baz": 128, + } + _, err := s1.Encode("sid", value) + if err != errHashKeyNotSet { + t.Fatal("Wrong error returned:", err) + } +} + +func TestDecodeInvalid(t *testing.T) { + // List of invalid cookies, which must not be accepted, base64-decoded + // (they will be encoded before passing to Decode). + invalidCookies := []string{ + "", + " ", + "\n", + "||", + "|||", + "cookie", + } + s := New([]byte("12345"), nil) + var dst string + for i, v := range invalidCookies { + for _, enc := range []*base64.Encoding{ + base64.StdEncoding, + base64.URLEncoding, + } { + err := s.Decode("name", enc.EncodeToString([]byte(v)), &dst) + if err == nil { + t.Fatalf("%d: expected failure decoding", i) + } + err2, ok := err.(Error) + if !ok || !err2.IsDecode() { + t.Fatalf("%d: Expected IsDecode(), got: %#v", i, err) + } + } + } +} + +func TestAuthentication(t *testing.T) { + hash := hmac.New(sha256.New, []byte("secret-key")) + for _, value := range testStrings { + hash.Reset() + signed := createMac(hash, []byte(value)) + hash.Reset() + err := verifyMac(hash, []byte(value), signed) + if err != nil { + t.Error(err) + } + } +} + +func TestEncryption(t *testing.T) { + block, err := aes.NewCipher([]byte("1234567890123456")) + if err != nil { + t.Fatalf("Block could not be created") + } + var encrypted, decrypted []byte + for _, value := range testStrings { + if encrypted, err = encrypt(block, []byte(value)); err != nil { + t.Error(err) + } else { + if decrypted, err = decrypt(block, encrypted); err != nil { + t.Error(err) + } + if string(decrypted) != value { + t.Errorf("Expected %v, got %v.", value, string(decrypted)) + } + } + } +} + +func TestGobSerialization(t *testing.T) { + var ( + sz GobEncoder + serialized []byte + deserialized map[string]string + err error + ) + for _, value := range testCookies { + if serialized, err = sz.Serialize(value); err != nil { + t.Error(err) + } else { + deserialized = make(map[string]string) + if err = sz.Deserialize(serialized, &deserialized); err != nil { + t.Error(err) + } + if fmt.Sprintf("%v", deserialized) != fmt.Sprintf("%v", value) { + t.Errorf("Expected %v, got %v.", value, deserialized) + } + } + } +} + +func TestJSONSerialization(t *testing.T) { + var ( + sz JSONEncoder + serialized []byte + deserialized map[string]string + err error + ) + for _, value := range testCookies { + if serialized, err = sz.Serialize(value); err != nil { + t.Error(err) + } else { + deserialized = make(map[string]string) + if err = sz.Deserialize(serialized, &deserialized); err != nil { + t.Error(err) + } + if fmt.Sprintf("%v", deserialized) != fmt.Sprintf("%v", value) { + t.Errorf("Expected %v, got %v.", value, deserialized) + } + } + } +} + +func TestNopSerialization(t *testing.T) { + cookieData := "fooobar123" + sz := NopEncoder{} + + if _, err := sz.Serialize(cookieData); err != errValueNotByte { + t.Fatal("Expected error passing string") + } + dat, err := sz.Serialize([]byte(cookieData)) + if err != nil { + t.Fatal(err) + } + if (string(dat)) != cookieData { + t.Fatal("Expected serialized data to be same as source") + } + + var dst []byte + if err = sz.Deserialize(dat, dst); err != errValueNotBytePtr { + t.Fatal("Expect error unless you pass a *[]byte") + } + if err = sz.Deserialize(dat, &dst); err != nil { + t.Fatal(err) + } + if (string(dst)) != cookieData { + t.Fatal("Expected deserialized data to be same as source") + } +} + +func TestEncoding(t *testing.T) { + for _, value := range testStrings { + encoded := encode([]byte(value)) + decoded, err := decode(encoded) + if err != nil { + t.Error(err) + } else if string(decoded) != value { + t.Errorf("Expected %v, got %s.", value, string(decoded)) + } + } +} + +func TestMultiError(t *testing.T) { + s1, s2 := New(nil, nil), New(nil, nil) + _, err := EncodeMulti("sid", "value", s1, s2) + if len(err.(MultiError)) != 2 { + t.Errorf("Expected 2 errors, got %s.", err) + } else { + if strings.Index(err.Error(), "hash key is not set") == -1 { + t.Errorf("Expected missing hash key error, got %s.", err.Error()) + } + ourErr, ok := err.(Error) + if !ok || !ourErr.IsUsage() { + t.Fatalf("Expected error to be a usage error; got %#v", err) + } + if ourErr.IsDecode() { + t.Errorf("Expected error NOT to be a decode error; got %#v", ourErr) + } + if ourErr.IsInternal() { + t.Errorf("Expected error NOT to be an internal error; got %#v", ourErr) + } + } +} + +func TestMultiNoCodecs(t *testing.T) { + _, err := EncodeMulti("foo", "bar") + if err != errNoCodecs { + t.Errorf("EncodeMulti: bad value for error, got: %v", err) + } + + var dst []byte + err = DecodeMulti("foo", "bar", &dst) + if err != errNoCodecs { + t.Errorf("DecodeMulti: bad value for error, got: %v", err) + } +} + +func TestMissingKey(t *testing.T) { + s1 := New(nil, nil) + + var dst []byte + err := s1.Decode("sid", "value", &dst) + if err != errHashKeyNotSet { + t.Fatalf("Expected %#v, got %#v", errHashKeyNotSet, err) + } + if err2, ok := err.(Error); !ok || !err2.IsUsage() { + t.Errorf("Expected missing hash key to be IsUsage(); was %#v", err) + } +} + +// ---------------------------------------------------------------------------- + +type FooBar struct { + Foo int + Bar string +} + +func TestCustomType(t *testing.T) { + s1 := New([]byte("12345"), []byte("1234567890123456")) + // Type is not registered in gob. (!!!) + src := &FooBar{42, "bar"} + encoded, _ := s1.Encode("sid", src) + + dst := &FooBar{} + _ = s1.Decode("sid", encoded, dst) + if dst.Foo != 42 || dst.Bar != "bar" { + t.Fatalf("Expected %#v, got %#v", src, dst) + } +} diff --git a/contrib/backends/nntpchand/src/vendor/github.com/gorilla/sessions/.travis.yml b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/sessions/.travis.yml new file mode 100644 index 0000000..db17dd3 --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/sessions/.travis.yml @@ -0,0 +1,22 @@ +language: go +sudo: false + +matrix: + include: + - go: 1.3 + - go: 1.4 + - go: 1.5 + - go: 1.6 + - go: 1.7 + - go: tip + allow_failures: + - go: tip + +install: + - # skip + +script: + - go get -t -v ./... + - diff -u <(echo -n) <(gofmt -d .) + - go vet $(go list ./... | grep -v /vendor/) + - go test -v -race ./... diff --git a/contrib/backends/nntpchand/src/vendor/github.com/gorilla/sessions/LICENSE b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/sessions/LICENSE new file mode 100644 index 0000000..0e5fb87 --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/sessions/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2012 Rodrigo Moraes. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/contrib/backends/nntpchand/src/vendor/github.com/gorilla/sessions/README.md b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/sessions/README.md new file mode 100644 index 0000000..ebc60d0 --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/sessions/README.md @@ -0,0 +1,90 @@ +sessions +======== +[![GoDoc](https://godoc.org/github.com/gorilla/sessions?status.svg)](https://godoc.org/github.com/gorilla/sessions) [![Build Status](https://travis-ci.org/gorilla/sessions.png?branch=master)](https://travis-ci.org/gorilla/sessions) +[![Sourcegraph](https://sourcegraph.com/github.com/gorilla/sessions/-/badge.svg)](https://sourcegraph.com/github.com/gorilla/sessions?badge) + + +gorilla/sessions provides cookie and filesystem sessions and infrastructure for +custom session backends. + +The key features are: + +* Simple API: use it as an easy way to set signed (and optionally + encrypted) cookies. +* Built-in backends to store sessions in cookies or the filesystem. +* Flash messages: session values that last until read. +* Convenient way to switch session persistency (aka "remember me") and set + other attributes. +* Mechanism to rotate authentication and encryption keys. +* Multiple sessions per request, even using different backends. +* Interfaces and infrastructure for custom session backends: sessions from + different stores can be retrieved and batch-saved using a common API. + +Let's start with an example that shows the sessions API in a nutshell: + +```go + import ( + "net/http" + "github.com/gorilla/sessions" + ) + + var store = sessions.NewCookieStore([]byte("something-very-secret")) + + func MyHandler(w http.ResponseWriter, r *http.Request) { + // Get a session. We're ignoring the error resulted from decoding an + // existing session: Get() always returns a session, even if empty. + session, _ := store.Get(r, "session-name") + // Set some session values. + session.Values["foo"] = "bar" + session.Values[42] = 43 + // Save it before we write to the response/return from the handler. + session.Save(r, w) + } +``` + +First we initialize a session store calling `NewCookieStore()` and passing a +secret key used to authenticate the session. Inside the handler, we call +`store.Get()` to retrieve an existing session or a new one. Then we set some +session values in session.Values, which is a `map[interface{}]interface{}`. +And finally we call `session.Save()` to save the session in the response. + +Important Note: If you aren't using gorilla/mux, you need to wrap your handlers +with +[`context.ClearHandler`](http://www.gorillatoolkit.org/pkg/context#ClearHandler) +as or else you will leak memory! An easy way to do this is to wrap the top-level +mux when calling http.ListenAndServe: + +```go + http.ListenAndServe(":8080", context.ClearHandler(http.DefaultServeMux)) +``` + +The ClearHandler function is provided by the gorilla/context package. + +More examples are available [on the Gorilla +website](http://www.gorillatoolkit.org/pkg/sessions). + +## Store Implementations + +Other implementations of the `sessions.Store` interface: + +* [github.com/starJammer/gorilla-sessions-arangodb](https://github.com/starJammer/gorilla-sessions-arangodb) - ArangoDB +* [github.com/yosssi/boltstore](https://github.com/yosssi/boltstore) - Bolt +* [github.com/srinathgs/couchbasestore](https://github.com/srinathgs/couchbasestore) - Couchbase +* [github.com/denizeren/dynamostore](https://github.com/denizeren/dynamostore) - Dynamodb on AWS +* [github.com/savaki/dynastore](https://github.com/savaki/dynastore) - DynamoDB on AWS (Official AWS library) +* [github.com/bradleypeabody/gorilla-sessions-memcache](https://github.com/bradleypeabody/gorilla-sessions-memcache) - Memcache +* [github.com/dsoprea/go-appengine-sessioncascade](https://github.com/dsoprea/go-appengine-sessioncascade) - Memcache/Datastore/Context in AppEngine +* [github.com/kidstuff/mongostore](https://github.com/kidstuff/mongostore) - MongoDB +* [github.com/srinathgs/mysqlstore](https://github.com/srinathgs/mysqlstore) - MySQL +* [github.com/EnumApps/clustersqlstore](https://github.com/EnumApps/clustersqlstore) - MySQL Cluster +* [github.com/antonlindstrom/pgstore](https://github.com/antonlindstrom/pgstore) - PostgreSQL +* [github.com/boj/redistore](https://github.com/boj/redistore) - Redis +* [github.com/boj/rethinkstore](https://github.com/boj/rethinkstore) - RethinkDB +* [github.com/boj/riakstore](https://github.com/boj/riakstore) - Riak +* [github.com/michaeljs1990/sqlitestore](https://github.com/michaeljs1990/sqlitestore) - SQLite +* [github.com/wader/gormstore](https://github.com/wader/gormstore) - GORM (MySQL, PostgreSQL, SQLite) +* [github.com/gernest/qlstore](https://github.com/gernest/qlstore) - ql + +## License + +BSD licensed. See the LICENSE file for details. diff --git a/contrib/backends/nntpchand/src/vendor/github.com/gorilla/sessions/doc.go b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/sessions/doc.go new file mode 100644 index 0000000..668e05e --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/sessions/doc.go @@ -0,0 +1,199 @@ +// Copyright 2012 The Gorilla 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 sessions provides cookie and filesystem sessions and +infrastructure for custom session backends. + +The key features are: + + * Simple API: use it as an easy way to set signed (and optionally + encrypted) cookies. + * Built-in backends to store sessions in cookies or the filesystem. + * Flash messages: session values that last until read. + * Convenient way to switch session persistency (aka "remember me") and set + other attributes. + * Mechanism to rotate authentication and encryption keys. + * Multiple sessions per request, even using different backends. + * Interfaces and infrastructure for custom session backends: sessions from + different stores can be retrieved and batch-saved using a common API. + +Let's start with an example that shows the sessions API in a nutshell: + + import ( + "net/http" + "github.com/gorilla/sessions" + ) + + var store = sessions.NewCookieStore([]byte("something-very-secret")) + + func MyHandler(w http.ResponseWriter, r *http.Request) { + // Get a session. We're ignoring the error resulted from decoding an + // existing session: Get() always returns a session, even if empty. + session, err := store.Get(r, "session-name") + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + // Set some session values. + session.Values["foo"] = "bar" + session.Values[42] = 43 + // Save it before we write to the response/return from the handler. + session.Save(r, w) + } + +First we initialize a session store calling NewCookieStore() and passing a +secret key used to authenticate the session. Inside the handler, we call +store.Get() to retrieve an existing session or a new one. Then we set some +session values in session.Values, which is a map[interface{}]interface{}. +And finally we call session.Save() to save the session in the response. + +Note that in production code, we should check for errors when calling +session.Save(r, w), and either display an error message or otherwise handle it. + +Save must be called before writing to the response, otherwise the session +cookie will not be sent to the client. + +Important Note: If you aren't using gorilla/mux, you need to wrap your handlers +with context.ClearHandler as or else you will leak memory! An easy way to do this +is to wrap the top-level mux when calling http.ListenAndServe: + + http.ListenAndServe(":8080", context.ClearHandler(http.DefaultServeMux)) + +The ClearHandler function is provided by the gorilla/context package. + +That's all you need to know for the basic usage. Let's take a look at other +options, starting with flash messages. + +Flash messages are session values that last until read. The term appeared with +Ruby On Rails a few years back. When we request a flash message, it is removed +from the session. To add a flash, call session.AddFlash(), and to get all +flashes, call session.Flashes(). Here is an example: + + func MyHandler(w http.ResponseWriter, r *http.Request) { + // Get a session. + session, err := store.Get(r, "session-name") + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + // Get the previously flashes, if any. + if flashes := session.Flashes(); len(flashes) > 0 { + // Use the flash values. + } else { + // Set a new flash. + session.AddFlash("Hello, flash messages world!") + } + session.Save(r, w) + } + +Flash messages are useful to set information to be read after a redirection, +like after form submissions. + +There may also be cases where you want to store a complex datatype within a +session, such as a struct. Sessions are serialised using the encoding/gob package, +so it is easy to register new datatypes for storage in sessions: + + import( + "encoding/gob" + "github.com/gorilla/sessions" + ) + + type Person struct { + FirstName string + LastName string + Email string + Age int + } + + type M map[string]interface{} + + func init() { + + gob.Register(&Person{}) + gob.Register(&M{}) + } + +As it's not possible to pass a raw type as a parameter to a function, gob.Register() +relies on us passing it a value of the desired type. In the example above we've passed +it a pointer to a struct and a pointer to a custom type representing a +map[string]interface. (We could have passed non-pointer values if we wished.) This will +then allow us to serialise/deserialise values of those types to and from our sessions. + +Note that because session values are stored in a map[string]interface{}, there's +a need to type-assert data when retrieving it. We'll use the Person struct we registered above: + + func MyHandler(w http.ResponseWriter, r *http.Request) { + session, err := store.Get(r, "session-name") + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + // Retrieve our struct and type-assert it + val := session.Values["person"] + var person = &Person{} + if person, ok := val.(*Person); !ok { + // Handle the case that it's not an expected type + } + + // Now we can use our person object + } + +By default, session cookies last for a month. This is probably too long for +some cases, but it is easy to change this and other attributes during +runtime. Sessions can be configured individually or the store can be +configured and then all sessions saved using it will use that configuration. +We access session.Options or store.Options to set a new configuration. The +fields are basically a subset of http.Cookie fields. Let's change the +maximum age of a session to one week: + + session.Options = &sessions.Options{ + Path: "/", + MaxAge: 86400 * 7, + HttpOnly: true, + } + +Sometimes we may want to change authentication and/or encryption keys without +breaking existing sessions. The CookieStore supports key rotation, and to use +it you just need to set multiple authentication and encryption keys, in pairs, +to be tested in order: + + var store = sessions.NewCookieStore( + []byte("new-authentication-key"), + []byte("new-encryption-key"), + []byte("old-authentication-key"), + []byte("old-encryption-key"), + ) + +New sessions will be saved using the first pair. Old sessions can still be +read because the first pair will fail, and the second will be tested. This +makes it easy to "rotate" secret keys and still be able to validate existing +sessions. Note: for all pairs the encryption key is optional; set it to nil +or omit it and and encryption won't be used. + +Multiple sessions can be used in the same request, even with different +session backends. When this happens, calling Save() on each session +individually would be cumbersome, so we have a way to save all sessions +at once: it's sessions.Save(). Here's an example: + + var store = sessions.NewCookieStore([]byte("something-very-secret")) + + func MyHandler(w http.ResponseWriter, r *http.Request) { + // Get a session and set a value. + session1, _ := store.Get(r, "session-one") + session1.Values["foo"] = "bar" + // Get another session and set another value. + session2, _ := store.Get(r, "session-two") + session2.Values[42] = 43 + // Save all sessions. + sessions.Save(r, w) + } + +This is possible because when we call Get() from a session store, it adds the +session to a common registry. Save() uses it to save all registered sessions. +*/ +package sessions diff --git a/contrib/backends/nntpchand/src/vendor/github.com/gorilla/sessions/lex.go b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/sessions/lex.go new file mode 100644 index 0000000..4bbbe10 --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/sessions/lex.go @@ -0,0 +1,102 @@ +// This file contains code adapted from the Go standard library +// https://github.com/golang/go/blob/39ad0fd0789872f9469167be7fe9578625ff246e/src/net/http/lex.go + +package sessions + +import "strings" + +var isTokenTable = [127]bool{ + '!': true, + '#': true, + '$': true, + '%': true, + '&': true, + '\'': true, + '*': true, + '+': true, + '-': true, + '.': true, + '0': true, + '1': true, + '2': true, + '3': true, + '4': true, + '5': true, + '6': true, + '7': true, + '8': true, + '9': true, + 'A': true, + 'B': true, + 'C': true, + 'D': true, + 'E': true, + 'F': true, + 'G': true, + 'H': true, + 'I': true, + 'J': true, + 'K': true, + 'L': true, + 'M': true, + 'N': true, + 'O': true, + 'P': true, + 'Q': true, + 'R': true, + 'S': true, + 'T': true, + 'U': true, + 'W': true, + 'V': true, + 'X': true, + 'Y': true, + 'Z': true, + '^': true, + '_': true, + '`': true, + 'a': true, + 'b': true, + 'c': true, + 'd': true, + 'e': true, + 'f': true, + 'g': true, + 'h': true, + 'i': true, + 'j': true, + 'k': true, + 'l': true, + 'm': true, + 'n': true, + 'o': true, + 'p': true, + 'q': true, + 'r': true, + 's': true, + 't': true, + 'u': true, + 'v': true, + 'w': true, + 'x': true, + 'y': true, + 'z': true, + '|': true, + '~': true, +} + +func isToken(r rune) bool { + i := int(r) + return i < len(isTokenTable) && isTokenTable[i] +} + +func isNotToken(r rune) bool { + return !isToken(r) +} + +func isCookieNameValid(raw string) bool { + if raw == "" { + return false + } + return strings.IndexFunc(raw, isNotToken) < 0 +} diff --git a/contrib/backends/nntpchand/src/vendor/github.com/gorilla/sessions/sessions.go b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/sessions/sessions.go new file mode 100644 index 0000000..fe0d2bc --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/sessions/sessions.go @@ -0,0 +1,241 @@ +// Copyright 2012 The Gorilla 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 sessions + +import ( + "encoding/gob" + "fmt" + "net/http" + "time" + + "github.com/gorilla/context" +) + +// Default flashes key. +const flashesKey = "_flash" + +// Options -------------------------------------------------------------------- + +// Options stores configuration for a session or session store. +// +// Fields are a subset of http.Cookie fields. +type Options struct { + Path string + Domain string + // MaxAge=0 means no 'Max-Age' attribute specified. + // MaxAge<0 means delete cookie now, equivalently 'Max-Age: 0'. + // MaxAge>0 means Max-Age attribute present and given in seconds. + MaxAge int + Secure bool + HttpOnly bool +} + +// Session -------------------------------------------------------------------- + +// NewSession is called by session stores to create a new session instance. +func NewSession(store Store, name string) *Session { + return &Session{ + Values: make(map[interface{}]interface{}), + store: store, + name: name, + } +} + +// Session stores the values and optional configuration for a session. +type Session struct { + // The ID of the session, generated by stores. It should not be used for + // user data. + ID string + // Values contains the user-data for the session. + Values map[interface{}]interface{} + Options *Options + IsNew bool + store Store + name string +} + +// Flashes returns a slice of flash messages from the session. +// +// A single variadic argument is accepted, and it is optional: it defines +// the flash key. If not defined "_flash" is used by default. +func (s *Session) Flashes(vars ...string) []interface{} { + var flashes []interface{} + key := flashesKey + if len(vars) > 0 { + key = vars[0] + } + if v, ok := s.Values[key]; ok { + // Drop the flashes and return it. + delete(s.Values, key) + flashes = v.([]interface{}) + } + return flashes +} + +// AddFlash adds a flash message to the session. +// +// A single variadic argument is accepted, and it is optional: it defines +// the flash key. If not defined "_flash" is used by default. +func (s *Session) AddFlash(value interface{}, vars ...string) { + key := flashesKey + if len(vars) > 0 { + key = vars[0] + } + var flashes []interface{} + if v, ok := s.Values[key]; ok { + flashes = v.([]interface{}) + } + s.Values[key] = append(flashes, value) +} + +// Save is a convenience method to save this session. It is the same as calling +// store.Save(request, response, session). You should call Save before writing to +// the response or returning from the handler. +func (s *Session) Save(r *http.Request, w http.ResponseWriter) error { + return s.store.Save(r, w, s) +} + +// Name returns the name used to register the session. +func (s *Session) Name() string { + return s.name +} + +// Store returns the session store used to register the session. +func (s *Session) Store() Store { + return s.store +} + +// Registry ------------------------------------------------------------------- + +// sessionInfo stores a session tracked by the registry. +type sessionInfo struct { + s *Session + e error +} + +// contextKey is the type used to store the registry in the context. +type contextKey int + +// registryKey is the key used to store the registry in the context. +const registryKey contextKey = 0 + +// GetRegistry returns a registry instance for the current request. +func GetRegistry(r *http.Request) *Registry { + registry := context.Get(r, registryKey) + if registry != nil { + return registry.(*Registry) + } + newRegistry := &Registry{ + request: r, + sessions: make(map[string]sessionInfo), + } + context.Set(r, registryKey, newRegistry) + return newRegistry +} + +// Registry stores sessions used during a request. +type Registry struct { + request *http.Request + sessions map[string]sessionInfo +} + +// Get registers and returns a session for the given name and session store. +// +// It returns a new session if there are no sessions registered for the name. +func (s *Registry) Get(store Store, name string) (session *Session, err error) { + if !isCookieNameValid(name) { + return nil, fmt.Errorf("sessions: invalid character in cookie name: %s", name) + } + if info, ok := s.sessions[name]; ok { + session, err = info.s, info.e + } else { + session, err = store.New(s.request, name) + session.name = name + s.sessions[name] = sessionInfo{s: session, e: err} + } + session.store = store + return +} + +// Save saves all sessions registered for the current request. +func (s *Registry) Save(w http.ResponseWriter) error { + var errMulti MultiError + for name, info := range s.sessions { + session := info.s + if session.store == nil { + errMulti = append(errMulti, fmt.Errorf( + "sessions: missing store for session %q", name)) + } else if err := session.store.Save(s.request, w, session); err != nil { + errMulti = append(errMulti, fmt.Errorf( + "sessions: error saving session %q -- %v", name, err)) + } + } + if errMulti != nil { + return errMulti + } + return nil +} + +// Helpers -------------------------------------------------------------------- + +func init() { + gob.Register([]interface{}{}) +} + +// Save saves all sessions used during the current request. +func Save(r *http.Request, w http.ResponseWriter) error { + return GetRegistry(r).Save(w) +} + +// NewCookie returns an http.Cookie with the options set. It also sets +// the Expires field calculated based on the MaxAge value, for Internet +// Explorer compatibility. +func NewCookie(name, value string, options *Options) *http.Cookie { + cookie := &http.Cookie{ + Name: name, + Value: value, + Path: options.Path, + Domain: options.Domain, + MaxAge: options.MaxAge, + Secure: options.Secure, + HttpOnly: options.HttpOnly, + } + if options.MaxAge > 0 { + d := time.Duration(options.MaxAge) * time.Second + cookie.Expires = time.Now().Add(d) + } else if options.MaxAge < 0 { + // Set it to the past to expire now. + cookie.Expires = time.Unix(1, 0) + } + return cookie +} + +// Error ---------------------------------------------------------------------- + +// MultiError stores multiple errors. +// +// Borrowed from the App Engine SDK. +type MultiError []error + +func (m MultiError) Error() string { + s, n := "", 0 + for _, e := range m { + if e != nil { + if n == 0 { + s = e.Error() + } + n++ + } + } + switch n { + case 0: + return "(0 errors)" + case 1: + return s + case 2: + return s + " (and 1 other error)" + } + return fmt.Sprintf("%s (and %d other errors)", s, n-1) +} diff --git a/contrib/backends/nntpchand/src/vendor/github.com/gorilla/sessions/sessions_test.go b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/sessions/sessions_test.go new file mode 100644 index 0000000..c166b05 --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/sessions/sessions_test.go @@ -0,0 +1,160 @@ +// Copyright 2012 The Gorilla 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 sessions + +import ( + "bytes" + "encoding/gob" + "net/http" + "net/http/httptest" + "testing" +) + +// NewRecorder returns an initialized ResponseRecorder. +func NewRecorder() *httptest.ResponseRecorder { + return &httptest.ResponseRecorder{ + HeaderMap: make(http.Header), + Body: new(bytes.Buffer), + } +} + +// DefaultRemoteAddr is the default remote address to return in RemoteAddr if +// an explicit DefaultRemoteAddr isn't set on ResponseRecorder. +const DefaultRemoteAddr = "1.2.3.4" + +// ---------------------------------------------------------------------------- + +type FlashMessage struct { + Type int + Message string +} + +func TestFlashes(t *testing.T) { + var req *http.Request + var rsp *httptest.ResponseRecorder + var hdr http.Header + var err error + var ok bool + var cookies []string + var session *Session + var flashes []interface{} + + store := NewCookieStore([]byte("secret-key")) + + // Round 1 ---------------------------------------------------------------- + + req, _ = http.NewRequest("GET", "http://localhost:8080/", nil) + rsp = NewRecorder() + // Get a session. + if session, err = store.Get(req, "session-key"); err != nil { + t.Fatalf("Error getting session: %v", err) + } + // Get a flash. + flashes = session.Flashes() + if len(flashes) != 0 { + t.Errorf("Expected empty flashes; Got %v", flashes) + } + // Add some flashes. + session.AddFlash("foo") + session.AddFlash("bar") + // Custom key. + session.AddFlash("baz", "custom_key") + // Save. + if err = Save(req, rsp); err != nil { + t.Fatalf("Error saving session: %v", err) + } + hdr = rsp.Header() + cookies, ok = hdr["Set-Cookie"] + if !ok || len(cookies) != 1 { + t.Fatal("No cookies. Header:", hdr) + } + + if _, err = store.Get(req, "session:key"); err.Error() != "sessions: invalid character in cookie name: session:key" { + t.Fatalf("Expected error due to invalid cookie name") + } + + // Round 2 ---------------------------------------------------------------- + + req, _ = http.NewRequest("GET", "http://localhost:8080/", nil) + req.Header.Add("Cookie", cookies[0]) + rsp = NewRecorder() + // Get a session. + if session, err = store.Get(req, "session-key"); err != nil { + t.Fatalf("Error getting session: %v", err) + } + // Check all saved values. + flashes = session.Flashes() + if len(flashes) != 2 { + t.Fatalf("Expected flashes; Got %v", flashes) + } + if flashes[0] != "foo" || flashes[1] != "bar" { + t.Errorf("Expected foo,bar; Got %v", flashes) + } + flashes = session.Flashes() + if len(flashes) != 0 { + t.Errorf("Expected dumped flashes; Got %v", flashes) + } + // Custom key. + flashes = session.Flashes("custom_key") + if len(flashes) != 1 { + t.Errorf("Expected flashes; Got %v", flashes) + } else if flashes[0] != "baz" { + t.Errorf("Expected baz; Got %v", flashes) + } + flashes = session.Flashes("custom_key") + if len(flashes) != 0 { + t.Errorf("Expected dumped flashes; Got %v", flashes) + } + + // Round 3 ---------------------------------------------------------------- + // Custom type + + req, _ = http.NewRequest("GET", "http://localhost:8080/", nil) + rsp = NewRecorder() + // Get a session. + if session, err = store.Get(req, "session-key"); err != nil { + t.Fatalf("Error getting session: %v", err) + } + // Get a flash. + flashes = session.Flashes() + if len(flashes) != 0 { + t.Errorf("Expected empty flashes; Got %v", flashes) + } + // Add some flashes. + session.AddFlash(&FlashMessage{42, "foo"}) + // Save. + if err = Save(req, rsp); err != nil { + t.Fatalf("Error saving session: %v", err) + } + hdr = rsp.Header() + cookies, ok = hdr["Set-Cookie"] + if !ok || len(cookies) != 1 { + t.Fatal("No cookies. Header:", hdr) + } + + // Round 4 ---------------------------------------------------------------- + // Custom type + + req, _ = http.NewRequest("GET", "http://localhost:8080/", nil) + req.Header.Add("Cookie", cookies[0]) + rsp = NewRecorder() + // Get a session. + if session, err = store.Get(req, "session-key"); err != nil { + t.Fatalf("Error getting session: %v", err) + } + // Check all saved values. + flashes = session.Flashes() + if len(flashes) != 1 { + t.Fatalf("Expected flashes; Got %v", flashes) + } + custom := flashes[0].(FlashMessage) + if custom.Type != 42 || custom.Message != "foo" { + t.Errorf("Expected %#v, got %#v", FlashMessage{42, "foo"}, custom) + } +} + +func init() { + gob.Register(FlashMessage{}) +} diff --git a/contrib/backends/nntpchand/src/vendor/github.com/gorilla/sessions/store.go b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/sessions/store.go new file mode 100644 index 0000000..4ff6b6c --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/sessions/store.go @@ -0,0 +1,295 @@ +// Copyright 2012 The Gorilla 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 sessions + +import ( + "encoding/base32" + "io/ioutil" + "net/http" + "os" + "path/filepath" + "strings" + "sync" + + "github.com/gorilla/securecookie" +) + +// Store is an interface for custom session stores. +// +// See CookieStore and FilesystemStore for examples. +type Store interface { + // Get should return a cached session. + Get(r *http.Request, name string) (*Session, error) + + // New should create and return a new session. + // + // Note that New should never return a nil session, even in the case of + // an error if using the Registry infrastructure to cache the session. + New(r *http.Request, name string) (*Session, error) + + // Save should persist session to the underlying store implementation. + Save(r *http.Request, w http.ResponseWriter, s *Session) error +} + +// CookieStore ---------------------------------------------------------------- + +// NewCookieStore returns a new CookieStore. +// +// Keys are defined in pairs to allow key rotation, but the common case is +// to set a single authentication key and optionally an encryption key. +// +// The first key in a pair is used for authentication and the second for +// encryption. The encryption key can be set to nil or omitted in the last +// pair, but the authentication key is required in all pairs. +// +// It is recommended to use an authentication key with 32 or 64 bytes. +// The encryption key, if set, must be either 16, 24, or 32 bytes to select +// AES-128, AES-192, or AES-256 modes. +// +// Use the convenience function securecookie.GenerateRandomKey() to create +// strong keys. +func NewCookieStore(keyPairs ...[]byte) *CookieStore { + cs := &CookieStore{ + Codecs: securecookie.CodecsFromPairs(keyPairs...), + Options: &Options{ + Path: "/", + MaxAge: 86400 * 30, + }, + } + + cs.MaxAge(cs.Options.MaxAge) + return cs +} + +// CookieStore stores sessions using secure cookies. +type CookieStore struct { + Codecs []securecookie.Codec + Options *Options // default configuration +} + +// Get returns a session for the given name after adding it to the registry. +// +// It returns a new session if the sessions doesn't exist. Access IsNew on +// the session to check if it is an existing session or a new one. +// +// It returns a new session and an error if the session exists but could +// not be decoded. +func (s *CookieStore) Get(r *http.Request, name string) (*Session, error) { + return GetRegistry(r).Get(s, name) +} + +// New returns a session for the given name without adding it to the registry. +// +// The difference between New() and Get() is that calling New() twice will +// decode the session data twice, while Get() registers and reuses the same +// decoded session after the first call. +func (s *CookieStore) New(r *http.Request, name string) (*Session, error) { + session := NewSession(s, name) + opts := *s.Options + session.Options = &opts + session.IsNew = true + var err error + if c, errCookie := r.Cookie(name); errCookie == nil { + err = securecookie.DecodeMulti(name, c.Value, &session.Values, + s.Codecs...) + if err == nil { + session.IsNew = false + } + } + return session, err +} + +// Save adds a single session to the response. +func (s *CookieStore) Save(r *http.Request, w http.ResponseWriter, + session *Session) error { + encoded, err := securecookie.EncodeMulti(session.Name(), session.Values, + s.Codecs...) + if err != nil { + return err + } + http.SetCookie(w, NewCookie(session.Name(), encoded, session.Options)) + return nil +} + +// MaxAge sets the maximum age for the store and the underlying cookie +// implementation. Individual sessions can be deleted by setting Options.MaxAge +// = -1 for that session. +func (s *CookieStore) MaxAge(age int) { + s.Options.MaxAge = age + + // Set the maxAge for each securecookie instance. + for _, codec := range s.Codecs { + if sc, ok := codec.(*securecookie.SecureCookie); ok { + sc.MaxAge(age) + } + } +} + +// FilesystemStore ------------------------------------------------------------ + +var fileMutex sync.RWMutex + +// NewFilesystemStore returns a new FilesystemStore. +// +// The path argument is the directory where sessions will be saved. If empty +// it will use os.TempDir(). +// +// See NewCookieStore() for a description of the other parameters. +func NewFilesystemStore(path string, keyPairs ...[]byte) *FilesystemStore { + if path == "" { + path = os.TempDir() + } + fs := &FilesystemStore{ + Codecs: securecookie.CodecsFromPairs(keyPairs...), + Options: &Options{ + Path: "/", + MaxAge: 86400 * 30, + }, + path: path, + } + + fs.MaxAge(fs.Options.MaxAge) + return fs +} + +// FilesystemStore stores sessions in the filesystem. +// +// It also serves as a reference for custom stores. +// +// This store is still experimental and not well tested. Feedback is welcome. +type FilesystemStore struct { + Codecs []securecookie.Codec + Options *Options // default configuration + path string +} + +// MaxLength restricts the maximum length of new sessions to l. +// If l is 0 there is no limit to the size of a session, use with caution. +// The default for a new FilesystemStore is 4096. +func (s *FilesystemStore) MaxLength(l int) { + for _, c := range s.Codecs { + if codec, ok := c.(*securecookie.SecureCookie); ok { + codec.MaxLength(l) + } + } +} + +// Get returns a session for the given name after adding it to the registry. +// +// See CookieStore.Get(). +func (s *FilesystemStore) Get(r *http.Request, name string) (*Session, error) { + return GetRegistry(r).Get(s, name) +} + +// New returns a session for the given name without adding it to the registry. +// +// See CookieStore.New(). +func (s *FilesystemStore) New(r *http.Request, name string) (*Session, error) { + session := NewSession(s, name) + opts := *s.Options + session.Options = &opts + session.IsNew = true + var err error + if c, errCookie := r.Cookie(name); errCookie == nil { + err = securecookie.DecodeMulti(name, c.Value, &session.ID, s.Codecs...) + if err == nil { + err = s.load(session) + if err == nil { + session.IsNew = false + } + } + } + return session, err +} + +// Save adds a single session to the response. +// +// If the Options.MaxAge of the session is <= 0 then the session file will be +// deleted from the store path. With this process it enforces the properly +// session cookie handling so no need to trust in the cookie management in the +// web browser. +func (s *FilesystemStore) Save(r *http.Request, w http.ResponseWriter, + session *Session) error { + // Delete if max-age is <= 0 + if session.Options.MaxAge <= 0 { + if err := s.erase(session); err != nil { + return err + } + http.SetCookie(w, NewCookie(session.Name(), "", session.Options)) + return nil + } + + if session.ID == "" { + // Because the ID is used in the filename, encode it to + // use alphanumeric characters only. + session.ID = strings.TrimRight( + base32.StdEncoding.EncodeToString( + securecookie.GenerateRandomKey(32)), "=") + } + if err := s.save(session); err != nil { + return err + } + encoded, err := securecookie.EncodeMulti(session.Name(), session.ID, + s.Codecs...) + if err != nil { + return err + } + http.SetCookie(w, NewCookie(session.Name(), encoded, session.Options)) + return nil +} + +// MaxAge sets the maximum age for the store and the underlying cookie +// implementation. Individual sessions can be deleted by setting Options.MaxAge +// = -1 for that session. +func (s *FilesystemStore) MaxAge(age int) { + s.Options.MaxAge = age + + // Set the maxAge for each securecookie instance. + for _, codec := range s.Codecs { + if sc, ok := codec.(*securecookie.SecureCookie); ok { + sc.MaxAge(age) + } + } +} + +// save writes encoded session.Values to a file. +func (s *FilesystemStore) save(session *Session) error { + encoded, err := securecookie.EncodeMulti(session.Name(), session.Values, + s.Codecs...) + if err != nil { + return err + } + filename := filepath.Join(s.path, "session_"+session.ID) + fileMutex.Lock() + defer fileMutex.Unlock() + return ioutil.WriteFile(filename, []byte(encoded), 0600) +} + +// load reads a file and decodes its content into session.Values. +func (s *FilesystemStore) load(session *Session) error { + filename := filepath.Join(s.path, "session_"+session.ID) + fileMutex.RLock() + defer fileMutex.RUnlock() + fdata, err := ioutil.ReadFile(filename) + if err != nil { + return err + } + if err = securecookie.DecodeMulti(session.Name(), string(fdata), + &session.Values, s.Codecs...); err != nil { + return err + } + return nil +} + +// delete session file +func (s *FilesystemStore) erase(session *Session) error { + filename := filepath.Join(s.path, "session_"+session.ID) + + fileMutex.RLock() + defer fileMutex.RUnlock() + + err := os.Remove(filename) + return err +} diff --git a/contrib/backends/nntpchand/src/vendor/github.com/gorilla/sessions/store_test.go b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/sessions/store_test.go new file mode 100644 index 0000000..bfc53fa --- /dev/null +++ b/contrib/backends/nntpchand/src/vendor/github.com/gorilla/sessions/store_test.go @@ -0,0 +1,125 @@ +package sessions + +import ( + "encoding/base64" + "net/http" + "net/http/httptest" + "testing" +) + +// Test for GH-8 for CookieStore +func TestGH8CookieStore(t *testing.T) { + originalPath := "/" + store := NewCookieStore() + store.Options.Path = originalPath + req, err := http.NewRequest("GET", "http://www.example.com", nil) + if err != nil { + t.Fatal("failed to create request", err) + } + + session, err := store.New(req, "hello") + if err != nil { + t.Fatal("failed to create session", err) + } + + store.Options.Path = "/foo" + if session.Options.Path != originalPath { + t.Fatalf("bad session path: got %q, want %q", session.Options.Path, originalPath) + } +} + +// Test for GH-8 for FilesystemStore +func TestGH8FilesystemStore(t *testing.T) { + originalPath := "/" + store := NewFilesystemStore("") + store.Options.Path = originalPath + req, err := http.NewRequest("GET", "http://www.example.com", nil) + if err != nil { + t.Fatal("failed to create request", err) + } + + session, err := store.New(req, "hello") + if err != nil { + t.Fatal("failed to create session", err) + } + + store.Options.Path = "/foo" + if session.Options.Path != originalPath { + t.Fatalf("bad session path: got %q, want %q", session.Options.Path, originalPath) + } +} + +// Test for GH-2. +func TestGH2MaxLength(t *testing.T) { + store := NewFilesystemStore("", []byte("some key")) + req, err := http.NewRequest("GET", "http://www.example.com", nil) + if err != nil { + t.Fatal("failed to create request", err) + } + w := httptest.NewRecorder() + + session, err := store.New(req, "my session") + session.Values["big"] = make([]byte, base64.StdEncoding.DecodedLen(4096*2)) + err = session.Save(req, w) + if err == nil { + t.Fatal("expected an error, got nil") + } + + store.MaxLength(4096 * 3) // A bit more than the value size to account for encoding overhead. + err = session.Save(req, w) + if err != nil { + t.Fatal("failed to Save:", err) + } +} + +// Test delete filesystem store with max-age: -1 +func TestGH8FilesystemStoreDelete(t *testing.T) { + store := NewFilesystemStore("", []byte("some key")) + req, err := http.NewRequest("GET", "http://www.example.com", nil) + if err != nil { + t.Fatal("failed to create request", err) + } + w := httptest.NewRecorder() + + session, err := store.New(req, "hello") + if err != nil { + t.Fatal("failed to create session", err) + } + + err = session.Save(req, w) + if err != nil { + t.Fatal("failed to save session", err) + } + + session.Options.MaxAge = -1 + err = session.Save(req, w) + if err != nil { + t.Fatal("failed to delete session", err) + } +} + +// Test delete filesystem store with max-age: 0 +func TestGH8FilesystemStoreDelete2(t *testing.T) { + store := NewFilesystemStore("", []byte("some key")) + req, err := http.NewRequest("GET", "http://www.example.com", nil) + if err != nil { + t.Fatal("failed to create request", err) + } + w := httptest.NewRecorder() + + session, err := store.New(req, "hello") + if err != nil { + t.Fatal("failed to create session", err) + } + + err = session.Save(req, w) + if err != nil { + t.Fatal("failed to save session", err) + } + + session.Options.MaxAge = 0 + err = session.Save(req, w) + if err != nil { + t.Fatal("failed to delete session", err) + } +}